標籤(空格分隔): 未分類html
重作了一遍,原本覺得很快的,結果搞了一天。。。ui
能夠發現只有\(\&0\)和\(|1\)會對答案有影響spa
那麼對於每一位,咱們只要知道最後一個\(\&1\)和最後一個\(|1\)誰近就能夠了。code
發現並很差作,咱們能夠把操做串也當成\(01\)串,若是\(\&=0,|=1\)好像並無什麼用,因而咱們令\(\&=1,|=0\)發現這樣恰好知足了咱們須要的信息,設\(op\)爲操做串,這一位串爲\(a\),若是\(op\)字典序小於\(a\)最後會是\(1\),不然爲\(0\)。(\(|1=01,\&0=10\)這就是字典序了,手玩也能夠htm
那麼咱們把原串基數排序,那麼必定能夠重排成\(00...011...1\),不然無解。若是有解那答案就是第一個\(1\)串表明的十進數值減掉最後一個\(0\)串十進制數值。注意下邊界條件。blog
\(code\)排序
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> #define gt getchar() #define ll long long #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) typedef std::pair<int,int> P; #define mk std::make_pair #define fr first #define sc second inline int in() { int k=0;char ch=gt;bool p=1; while(ch<'-')ch=gt;if(ch=='-')ch=gt,p=0; while(ch>'-')k=k*10+ch-'0',ch=gt; return p?k:-k; } const int YL=1e9+7,N=1005,M=5005; inline int ksm(int a,int k){int r=1;while(k){if(k&1)r=1ll*r*a%YL;a=1ll*a*a%YL,k>>=1;}return r;} inline int MO(const int &x){return x>=YL?x-YL:x;} int pw[M],s[N][M],id[2][M],rk[M],res[M]; int main() { int n=in(),m=in(),q=in(); for(int i=1;i<=n;++i) { static char S[M];scanf("%s",S+1); for(int j=1;j<=m;++j)s[i][j]=S[j]-'0'; } for(int i=1;i<=m;++i)id[0][i]=i; int now=0;pw[0]=1; for(int i=1;i<=n;++i) { now^=1;int cnt=0,tot=0;pw[i]=MO(pw[i-1]<<1); for(int j=1;j<=m;++j)cnt+=s[i][j]^1; for(int j=1;j<=m;++j) if(s[i][id[now^1][j]])id[now][++cnt]=id[now^1][j]; else id[now][++tot]=id[now^1][j]; } int *p=id[now]; for(int i=1;i<=m;++i)rk[p[i]]=i; for(int i=1;i<=m;++i) for(int j=1;j<=n;++j) res[i]=MO(res[i]+s[j][i]*pw[j-1]); res[m+1]=pw[n];p[m+1]=m+1; while(q--) { static char S[M];scanf("%s",S+1); int mx=-1,mi=m+1; for(int i=1;i<=m;++i) if(S[i]=='0')mx=std::max(mx,rk[i]); else mi=std::min(mi,rk[i]); if(mx>=mi){puts("0");continue;} printf("%d\n",MO(res[p[mi]]-res[p[mx]]+YL)); } return 0; }
能夠發現,走一圈是最優的。遊戲
那麼即求\(min(max(T_j-j)+i)+n-1\)。ip
樓房重建便可get
\(code\)
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> #define gt getchar() #define ll long long #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) typedef std::pair<int,int> P; #define mk std::make_pair #define fr first #define sc second inline int in() { int k=0;char ch=gt;bool p=1; while(ch<'-')ch=gt;if(ch=='-')ch=gt,p=0; while(ch>'-')k=k*10+ch-'0',ch=gt; return p?k:-k; } const int N=2e5+5; int mis[N<<2],mip[N<<2],mxv[N<<2],a[N]; #define lc k<<1 #define rc k<<1|1 #define ls l, mid ,lc #define rs mid+1,r,rc #define mid ((l+r)>>1) int calc(int mh,int l,int r,int k) { if(l==r)return std::max(mh,a[l])+l;int w=mxv[rc]; if(mh>=w)return std::min(calc(mh,ls),mh+mid+1); else return std::min(calc(mh,rs),mis[k]); } inline void up(int l,int r,int k) { mxv[k]=std::max(mxv[lc],mxv[rc]); mis[k]=calc(mxv[rc],ls); } void build(int l,int r,int k) { if(l==r)return mxv[k]=a[l],void(); build(ls),build(rs),up(l,r,k); } void upd(int l,int r,int k,int p) { if(l==r)return mxv[k]=a[l],void(); p<=mid?upd(ls,p):upd(rs,p);up(l,r,k); } int main() { int n=in(),m=in(),op=in(),ans=0; for(int i=1;i<=n;++i) a[i]=a[i+n]=in(),a[i]-=i,a[n+i]-=n+i; build(1,n<<1,1);printf("%d\n",ans=mis[1]+n-1); for(int i=1;i<=m;++i) { int x=in()^op*ans,y=in()^op*ans; a[x]=y-x;a[x+n]=y-x-n; upd(1,n<<1,1,x),upd(1,n<<1,1,x+n); printf("%d\n",ans=mis[1]+n-1); } return 0; }
以前的博客是我沒理解清寫的。
樹的\(dp\)是基礎,而後把返祖邊們摳出來建虛樹,枚舉兩端狀況。
這裏的\(f[u][0/1]\)是表示\(u\)取\(0/1\)的時候,子樹的方案數。
因此咱們只要枚舉返祖邊的祖先點的狀態就能夠了。
而後處理轉移係數\(xs[u][i=0/1][j=0/1]\)表示虛樹上的父親選\(i\),這個點選\(j\)的係數的轉移係數。
注意到邊是有影響的,因此不在虛樹上的點的\(xs\)表示的是該點選\(i\),這個點子樹內第一個虛點選\(j\)的係數,當咱們發現這個\(xs\)轉移到一個虛點時,直接把\(xs\)掛在後面那維表明的虛點上。
不在虛樹上的點記得乘上這個點選\(0/1\)的方案數。
在虛樹上的點的\(xs\)要使得\(xs[u][0][0]=xs[u][1][1]=1\)。
轉移的時候若是這個點被強制選了某個值,另外一的\(dp\)初值必須爲\(0\)。
\(code\)
#include<vector> #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> #define pb push_back #define gt getchar() #define ll long long #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) typedef std::pair<int,int> P; #define mk std::make_pair #define fr first #define sc second inline int in() { int k=0;char ch=gt;bool p=1; while(ch<'-')ch=gt;if(ch=='-')ch=gt,p=0; while(ch>'-')k=k*10+ch-'0',ch=gt; return p?k:-k; } const int YL=998244353,N=1e5+5;typedef std::vector<int> vi; inline int ksm(int a,int k){int r=1;while(k){if(k&1)r=1ll*r*a%YL;a=1ll*a*a%YL,k>>=1;}return r;} inline int MO(const int &x){return x>=YL?x-YL:x;} vi G[N],E[N];int xs[N][2][2],f[N][2],g[N][2],tsz[N],imp[N],o[N]; int Eu[N],Ev[N],tot,dep[N],fg[N][2],vis[N],tt; void pre_dfs(int u,int pa=0) { o[u]=++tt; for(int v:G[u])if(v==pa)continue; else if(!o[v])pre_dfs(v,u),tsz[u]+=tsz[v]; else { imp[u]=1; if(o[u]<o[v]) Eu[++tot]=u,Ev[tot]=v; } imp[u]|=tsz[u]>=2;tsz[u]=tsz[u]||imp[u]; } void mul(int f[2][2],int g[2][2]) { int f00=f[0][0],f01=f[0][1]; int f10=f[1][0],f11=f[1][1]; g[0][0]=MO(f00+f10); g[0][1]=MO(f01+f11); g[1][0]=f00,g[1][1]=f01; } inline void init(int f[2][2]){f[0][0]=f[1][1]=1,f[0][1]=f[1][0]=0;} int dfs(int u) { vis[u]=g[u][0]=g[u][1]=1;int pos=0; for(int v:G[u]) if(!vis[v]) { int w=dfs(v); if(!w) { g[u][0]=1ll*g[u][0]*(g[v][1]+g[v][0])%YL; g[u][1]=1ll*g[u][1]*g[v][0]%YL; } else if(!imp[u])mul(xs[v],xs[u]),pos=w; else mul(xs[v],xs[w]),E[u].pb(w),pos=w; } if(imp[u])return init(xs[u]),u; xs[u][0][0]=1ll*xs[u][0][0]*g[u][0]%YL; xs[u][0][1]=1ll*xs[u][0][1]*g[u][0]%YL; xs[u][1][0]=1ll*xs[u][1][0]*g[u][1]%YL; xs[u][1][1]=1ll*xs[u][1][1]*g[u][1]%YL; return pos; } void dp(int u) { f[u][0]=fg[u][1]?0:g[u][0]; f[u][1]=fg[u][0]?0:g[u][1]; for(int v:E[u]) { dp(v); for(int i=0;i<2;++i) f[u][i]=(1ll*xs[v][i][0]*f[v][0]+1ll*xs[v][i][1]*f[v][1])%YL*f[u][i]%YL; } } int main() { int n=in(),m=in(),ans=0; for(int i=1,u,v;i<=m;++i) u=in(),v=in(),G[u].pb(v),G[v].pb(u); pre_dfs(1),imp[1]=1,dfs(1);int mx=1<<tot; for(int i=0;i<mx;++i) { for(int j=0;j<tot;++j) if(i>>j&1)fg[Eu[j+1]][1]=1,fg[Ev[j+1]][0]=1; else fg[Eu[j+1]][0]=1; dp(1);ans=MO(ans+MO(f[1][1]+f[1][0])); for(int j=0;j<tot;++j) if(i>>j&1)fg[Eu[j+1]][1]=0,fg[Ev[j+1]][0]=0; else fg[Eu[j+1]][0]=0; } printf("%d\n",ans); return 0; }
咱們發現若是一個點能到\(L\),且另外一個點能到它,那麼另外一個點確定能到\(L\),因此咱們預處理\(L[i],R[i]\)爲\(i\)點能擴大的最大範圍。咱們須要安排一個順序使得他們最優。
若是一扇門\(x,x+1\)的鑰匙在\(1-x\)則確定要先轉移\(x+1\)再轉移\(x\),反之亦然。
因而咱們能夠拓撲排序。
問題的關鍵在於門是不滿的,因此有不少沒有關係的點之間跳來跳去,複雜度就假了。
可是因爲數據只卡了正着作的,沒卡反着作的,因而他的亂搞就能過(他寫了兩篇亂搞(小聲。
那咱們用並查集把沒有門的點縮起來就\(ok\)了。
\(code\)
#include<queue> #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> #define gt getchar() #define ll long long #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) typedef std::pair<int,int> P; #define mk std::make_pair #define fr first #define sc second inline int in() { int k=0;char ch=gt;bool p=1; while(ch<'-')ch=gt;if(ch=='-')ch=gt,p=0; while(ch>'-')k=k*10+ch-'0',ch=gt; return p?k:-k; } const int N=1e6+5; int head[N],to[N],du[N],p[N],L[N],R[N],nxt[N],cnt,key[N],tot,n,fa[N]; inline void add(int u,int v){to[++cnt]=v,nxt[cnt]=head[u],head[u]=cnt,++du[v];} int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);} inline void work(int u) { int l=L[u],r=R[u],nl,nr; while(1) { nl=l,nr=r; while(l>1&&(!key[l-1]||(l<=key[l-1]&&key[l-1]<=r)))l=L[find(l-1)]; while(r<n&&(!key[ r ]||(l<=key[ r ]&&key[ r ]<=r)))r=R[find(r+1)]; if(nl==l&&nr==r)break; } L[u]=l,R[u]=r; } int main() { n=in();int m=in(),q=in(); for(int i=1,x,y;i<=m;++i)x=in(),y=in(),key[x]=y; for(int i=1;i<=n;++i)fa[i]=i; for(int i=1;i<n;++i)if(!key[i])fa[i+1]=find(i); for(int i=1;i<n;++i) if(key[i]) { if(key[i]<=i)add(find(i+1),find(i)); else add(find(i),find(i+1)); } std::queue<int>Q; for(int i=1;i<=n;++i)if(fa[i]==i&&!du[i])Q.push(i); while(!Q.empty()) { int u=p[++tot]=Q.front();Q.pop(); for(int i=head[u];i;i=nxt[i]) if(!--du[to[i]])Q.push(to[i]); } for(int i=1;i<=n;++i)R[find(i)]=i; for(int i=n;i>=1;--i)L[find(i)]=i; for(int i=1;i<=tot;++i)work(p[i]); while(q--){int x=find(in()),y=find(in());puts(L[x]<=y&&y<=R[x]?"YES":"NO");} return 0; }
先把依賴關係的\(DAG\)建出來。
而後就是貪心,小的必定要儘可能放在前面。
考慮當前最小值,它在父親節點刪掉後必定會被刪。
因此能夠並起來,而後咱們如今是考慮一堆序列的順序,推下式子發現只要平均值小就必定先選,就沒了。
\(code\)
#include<cstdlib> #include<vector> #include<queue> #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> #define gt getchar() #define ll long long #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) #define mk std::make_pair #define fr first #define sc second #define double long double typedef std::pair<double,int> P; inline int in() { int k=0;char ch=gt;bool p=1; while(ch<'-')ch=gt;if(ch=='-')ch=gt,p=0; while(ch>'-')k=k*10+ch-'0',ch=gt; return p?k:-k; } typedef std::vector<int> vi; const int N=5e5+5;vi G[N]; const double eps=1e-6; int o[N],sz[N],fa[N],ff[N];ll w[N]; struct Queue { std::priority_queue<P>Q1,Q2; void push(P x){Q1.push(x);} void erase(P x){Q2.push(x);} void upd(){while(!Q2.empty()&&Q1.top()==Q2.top())Q1.pop(),Q2.pop();} inline void pop(){upd();Q1.pop();} inline P top(){upd();return Q1.top();} }Q; int dfs(int u) { int ans=u!=0;o[u]=1; for(int v:G[u]) if(o[v])puts("-1"),exit(0); else ans+=dfs(v);return ans; } int find(int x){return x==ff[x]?x:ff[x]=find(ff[x]);} int main() { int n=in();ll ans=0; for(int i=1;i<=n;++i)G[fa[i]=in()].push_back(i); for(int i=1;i<=n;++i)ans+=w[i]=in(); if(dfs(0)!=n)return puts("-1"),0; for(int i=1;i<=n;++i)ff[i]=i,sz[i]=1; for(int i=1;i<=n;++i)Q.push(mk(-(double)w[i],i)); for(int i=1;i<=n;++i) { P now=Q.top();Q.pop();int u=find(now.sc),v=find(fa[u]); if(v)Q.erase(mk(-(double)w[v]/sz[v],v)); ans+=w[u]*sz[v],w[v]+=w[u],sz[v]+=sz[u],ff[u]=v; if(v)Q.push(mk(-(double)w[v]/sz[v],v)); } printf("%lld\n",ans); return 0; }
普及\(dp\),設\(F[i][j][k]\)表示第\(i\)個城市,沒修的公路有\(j\)條,沒修的鐵路有\(k\)條的最小代價。
葉子節點直接算,非葉子節點枚舉修什麼。考場上好像卡空間,用分治的\(fft\)的卡空間技巧就好了
\(code\)
#include<vector> #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> #define gt getchar() #define ll long long #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) typedef std::pair<int,int> P; #define mk std::make_pair #define fr first #define sc second inline int in() { int k=0;char ch=gt;bool p=1; while(ch<'-')ch=gt;if(ch=='-')ch=gt,p=0; while(ch>'-')k=k*10+ch-'0',ch=gt; return p?k:-k; } typedef std::vector<int> vi; const int N=20005;vi G[N]; ll f[N][41][41],a[N],b[N],c[N]; ll dfs(int u,int L,int R) { if(u<0)return c[-u]*(a[-u]+L)*(b[-u]+R); if(~f[u][L][R])return f[u][L][R];int lc=G[u][0],rc=G[u][1]; return f[u][L][R]=std::min(dfs(lc,L+1,R)+dfs(rc,L,R),dfs(lc,L,R)+dfs(rc,L,R+1)); } int main() { int n=in(); for(int i=1;i<n;++i) { int s=in(),t=in(); G[i].push_back(s),G[i].push_back(t); } for(int i=1;i<=n;++i)a[i]=in(),b[i]=in(),c[i]=in(); memset(f,-1,sizeof f);printf("%lld\n",dfs(1,0,0)); return 0; }