2014 Multi-University Training Contest 3
官方解题报告http://blog.sina.com.cn/s/blog_a19ad7a10102uyiq.html
Wow! Such Sequence! http://acm.hdu.edu.cn/showproblem.php?pid=4893
线段树,比赛时写的不好。
1 #include<cstdio> 2 #include<algorithm> 3 #define lrrt int L,int R,int rt 4 #define iall 1,n,1 5 #define imid int mid=(L+R)>>1 6 #define lson L,mid,rt<<1 7 #define rson mid+1,R,rt<<1|1 8 using namespace std; 9 typedef __int64 LL; 10 const int M=100010; 11 struct T{ 12 LL sum; 13 bool cover; 14 }tree[M<<2]; 15 LL F[M]; 16 int Flen=92; 17 void initF(){ 18 F[0]=F[1]=1; 19 for(int i=2;i<Flen;i++){ 20 F[i]=F[i-1]+F[i-2]; 21 } 22 } 23 int Findcloseid(LL val){ 24 if(val<=1) return 0; 25 int id=lower_bound(F,F+Flen,val)-F; 26 if(abs(F[id-1]-val)<=abs(F[id]-val)) id--; 27 return id; 28 } 29 void pushup(int rt){ 30 tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum; 31 tree[rt].cover=tree[rt<<1].cover&tree[rt<<1|1].cover; 32 } 33 void build(lrrt){ 34 tree[rt].cover=0; 35 tree[rt].sum=0; 36 if(L==R) return ; 37 imid; 38 build(lson); 39 build(rson); 40 } 41 void add(int x,int val,lrrt){ 42 if(L==R){ 43 tree[rt].sum+=val; 44 int id=Findcloseid(tree[rt].sum); 45 tree[rt].cover=(F[id]==tree[rt].sum); 46 return ; 47 } 48 imid; 49 if(mid>=x) add(x,val,lson); 50 else add(x,val,rson); 51 pushup(rt); 52 } 53 void update(int x,int y,lrrt){ 54 if(L==R){ 55 tree[rt].cover=true; 56 tree[rt].sum=F[Findcloseid(tree[rt].sum)]; 57 return ; 58 } 59 imid; 60 if(x<=L&&R<=y){ 61 if(tree[rt].cover) return ; 62 update(x,y,lson); 63 update(x,y,rson); 64 pushup(rt); 65 return ; 66 } 67 if(mid>=x) update(x,y,lson); 68 if(mid<y) update(x,y,rson); 69 pushup(rt); 70 } 71 LL query(int x,int y,lrrt){ 72 if(x<=L&&R<=y) return tree[rt].sum; 73 imid; 74 LL ans=0; 75 if(mid>=x) ans+=query(x,y,lson); 76 if(mid<y) ans+=query(x,y,rson); 77 return ans; 78 } 79 int main(){ 80 initF(); 81 int n,m; 82 while(~scanf("%d%d",&n,&m)){ 83 build(iall); 84 while(m--){ 85 int op,x,y; 86 scanf("%d%d%d",&op,&x,&y); 87 if(op==1){ 88 add(x,y,iall); 89 } 90 else if(op==2){ 91 printf("%I64d\n",query(x,y,iall)); 92 } 93 else{ 94 update(x,y,iall); 95 } 96 } 97 } 98 return 0; 99 }
Scary Path Finding Algorithm http://acm.hdu.edu.cn/showproblem.php?pid=4889
1 #include<cstdio> 2 using namespace std; 3 int exp2[32],c; 4 int main() { 5 exp2[0] = 1; 6 for(int i = 1; i < 32; i++) { 7 exp2[i] = exp2[i-1] <<1; 8 } 9 while(~scanf("%d",&c)) { 10 puts("61 90"); 11 for(int i = 0,j; i < 30; i++) { 12 j=i<<1; 13 printf("%d %d %d\n",1+j,1+j+1,0); 14 printf("%d %d %d\n",1+j+1,1+j+2, -exp2[30-i]); 15 printf("%d %d %d\n",1+j,1+j+2, -exp2[29-i]); 16 } 17 } 18 return 0; 19 }
The Great Pan http://acm.hdu.edu.cn/showproblem.php?pid=4891
模拟题。
1 #include<cstdio> 2 #include<cstring> 3 typedef __int64 LL; 4 const int M=1024; 5 char a[M][M]; 6 int main(){ 7 int n; 8 while(~scanf("%d",&n)){ 9 getchar(); 10 for(int i=0;i<n;i++){ 11 gets(a[i]); 12 } 13 LL ans=1; 14 LL sa=0,sb=0;// ||| ' ' 15 bool fa=0,fb=0; 16 bool big=false; 17 for(int i=0;i<n;i++){ 18 if(big) break; 19 int len=strlen(a[i]); 20 for(int j=0;j<len;j++){ 21 if(big) break; 22 if(a[i][j]=='{'){ 23 fa=true; 24 sa=0; 25 } 26 else if(a[i][j]=='}'){ 27 fa=false; 28 ans*=(sa+1); 29 if(ans>100000) big=true; 30 sa=0; 31 } 32 else if(a[i][j]=='$'){ 33 if(fb){ 34 fb=false; 35 ans*=(sb+1); 36 sb=0; 37 } 38 else{ 39 fb=true; 40 sb=0; 41 } 42 } 43 else{ 44 if(fa){ 45 if(a[i][j]=='|'){ 46 sa++; 47 } 48 } 49 else if(fb){ 50 if(a[i][j]==' '){ 51 int k; 52 for(k=j;k<len;k++){ 53 if(a[i][k]==' ') sb++; 54 else break; 55 } 56 j=k-1; 57 if(k==len){ 58 if(i+1<n&&a[i+1][0]==' ') 59 continue; 60 } 61 ans*=(sb+1); 62 if(ans>100000) big=true; 63 sb=0; 64 } 65 } 66 } 67 } 68 } 69 if(big){ 70 puts("doge"); 71 continue; 72 } 73 printf("%I64d\n",ans); 74 } 75 return 0; 76 }
Redraw Beautiful Drawings http://acm.hdu.edu.cn/showproblem.php?pid=4888
最大流建图和判断多解有待研究。
我们建一个二部图,左边是行,右边是列,建个源点与行建边,容量是该行的和,列与新建的汇点建边,容量是该列的和,最后每行与每列建边,容量为题意中的k。建边如图:
跑一遍最大流,如果最大流等于行的和且等于列的和,那么就是有解的,否则无解。这样我们得到了一组解,行i到列j的流量即为i行j列的大小。之后便是判断是否有多种情况了。基本思路是这样的,我们看下图:
有多解的情况一定可以找到这样的4个位置:AB同行,CD同行,AC同列,BD同列,并且他们符合一下两种情况的其中一种:
1、AD未达到k(可变大),BC不是0(可减小)
2、AD不是0(可减小),BC未达到k(可变大)
不过枚举的话复杂度太高了,这里需要优化下。我建了一个二维数组cc[i][j],代表之前行是否有第i个可变大,第j个可减小的情况。这里枚举每一行,每一行再枚举两个位置i和j,如果当前行有i和j使得第i可以减小、第j个可以变大并且cc[i][j]为1,那么一定有多解。这里如果cc[i][j]为0,那么继续,同时cc[j][i]赋为1。这样的话就避免了最坏O(400^4)的复杂度,而变成了最多O(400^3)。
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #define mt(a,b) memset(a,b,sizeof(a)) 5 using namespace std; 6 const int inf=0x7fffffff; 7 const int M=1024; 8 class Sap { //最大流sap算法O(V*E^2) 9 int n,head[M],dep[M],gap[M],cur[M],S[M],res,top,i,inser; 10 queue<int> q; 11 void bfs(int s,int t) { 12 mt(dep,-1); 13 mt(gap,0); 14 while(!q.empty()) q.pop(); 15 gap[0]=1; 16 dep[t]=0; 17 q.push(t); 18 while(!q.empty()) { 19 int u=q.front(); 20 q.pop(); 21 for(int i=head[u]; ~i; i=e[i].next) { 22 int v=e[i].v; 23 if(dep[v]!=-1) continue; 24 q.push(v); 25 dep[v]=dep[u]+1; 26 ++gap[dep[v]]; 27 } 28 } 29 } 30 public: 31 struct E { 32 int u,v,next,flow; 33 } e[M*M]; 34 int le; 35 void init(int tn) { 36 n=tn; 37 le=0; 38 mt(head,-1); 39 } 40 void add(int u,int v,int flow) { 41 e[le].u=u; 42 e[le].v=v; 43 e[le].flow=flow; 44 e[le].next=head[u]; 45 head[u]=le++; 46 e[le].u=v; 47 e[le].v=u; 48 e[le].flow=0; 49 e[le].next=head[v]; 50 head[v]=le++; 51 } 52 int solve(int s,int t) { 53 bfs(s,t); 54 res=top=0; 55 for(i=0;i<=n;i++) cur[i]=head[i]; 56 int u=s; 57 while(dep[s]<n) { 58 if(u==t) { 59 int temp=inf; 60 for(i=0; i<top; i++) 61 if(temp>e[S[i]].flow) { 62 temp=e[S[i]].flow; 63 inser=i; 64 } 65 for(i=0; i<top; i++) { 66 e[S[i]].flow-=temp; 67 e[S[i]^1].flow+=temp; 68 } 69 res+=temp; 70 top=inser; 71 u=e[S[top]].u; 72 } 73 if(u!=t&&!gap[dep[u]-1]) break; 74 for(i=cur[u]; ~i; i=e[i].next) 75 if(e[i].flow&&dep[u]==dep[e[i].v]+1) 76 break; 77 if(~i) { 78 cur[u]=i; 79 S[top++]=i; 80 u=e[i].v; 81 } else { 82 int sma=n; 83 for(i=head[u]; ~i; i=e[i].next) { 84 if(!e[i].flow) continue; 85 if(sma>dep[e[i].v]) { 86 sma=dep[e[i].v]; 87 cur[u]=i; 88 } 89 } 90 --gap[dep[u]]; 91 dep[u]=sma+1; 92 ++gap[dep[u]]; 93 if(u!=s) u=e[S[--top]].u; 94 } 95 } 96 return res; 97 } 98 } gx; 99 int n,m,k,suma,sumb,a[M>>1],b[M>>1],mp[M>>1][M>>1]; 100 bool dou[M>>1][M>>1];//dou[0][i] i这列存在一个可增的点 101 int solve(){ 102 if(suma!=sumb) return -1; 103 int s=0,t=n+m+1; 104 gx.init(t+1); 105 for(int i=1;i<=n;i++){ 106 for(int j=1;j<=m;j++){ 107 gx.add(i,j+n,k); 108 } 109 } 110 for(int i=1;i<=n;i++){ 111 gx.add(s,i,a[i]); 112 } 113 for(int i=1;i<=m;i++){ 114 gx.add(i+n,t,b[i]); 115 } 116 if(gx.solve(s,t)!=suma) return -1; 117 int eid=1; 118 for(int i=1;i<=n;i++){ 119 for(int j=1;j<=m;j++,eid+=2){ 120 mp[i][j]=gx.e[eid].flow; 121 } 122 } 123 mt(dou,0); 124 for(int i=1;i<=n;i++){ 125 for(int j=1;j<=m;j++){ 126 for(int z=j+1;z<=m;z++){ 127 bool v1=false,v2=false; 128 if(mp[i][j]!=k&&mp[i][z]!=0){ 129 if(dou[z][j]) return 0; 130 v1=1; 131 } 132 if(mp[i][j]!=0&&mp[i][z]!=k){ 133 if(dou[j][z]) return 0; 134 v2=1; 135 } 136 if(v1) dou[j][z]=true; 137 if(v2) dou[z][j]=true; 138 } 139 } 140 } 141 return 1; 142 } 143 int main(){ 144 while(~scanf("%d%d%d",&n,&m,&k)){ 145 suma=sumb=0; 146 for(int i=1;i<=n;i++){ 147 scanf("%d",&a[i]); 148 suma+=a[i]; 149 } 150 for(int i=1;i<=m;i++){ 151 scanf("%d",&b[i]); 152 sumb+=b[i]; 153 } 154 int ans=solve(); 155 if(ans==-1){ 156 puts("Impossible"); 157 } 158 else if(!ans){ 159 puts("Not Unique"); 160 } 161 else{ 162 puts("Unique"); 163 for(int i=1;i<=n;i++){ 164 for(int j=1;j<=m;j++){ 165 if(j>1) printf(" "); 166 printf("%d",mp[i][j]); 167 } 168 puts(""); 169 } 170 } 171 } 172 }
李队随机法选点测试,随机100次能ac。佩服。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<queue> 5 #define mt(a,b) memset(a,b,sizeof(a)) 6 using namespace std; 7 const int inf=0x7fffffff; 8 const int M=1024; 9 class Sap { //最大流sap算法O(V*E^2) 10 int n,head[M],dep[M],gap[M],cur[M],S[M],res,top,i,inser; 11 queue<int> q; 12 void bfs(int s,int t) { 13 mt(dep,-1); 14 mt(gap,0); 15 while(!q.empty()) q.pop(); 16 gap[0]=1; 17 dep[t]=0; 18 q.push(t); 19 while(!q.empty()) { 20 int u=q.front(); 21 q.pop(); 22 for(int i=head[u]; ~i; i=e[i].next) { 23 int v=e[i].v; 24 if(dep[v]!=-1) continue; 25 q.push(v); 26 dep[v]=dep[u]+1; 27 ++gap[dep[v]]; 28 } 29 } 30 } 31 public: 32 struct E { 33 int u,v,next,flow; 34 } e[M*M]; 35 int le; 36 void init(int tn) { 37 n=tn; 38 le=0; 39 mt(head,-1); 40 } 41 void add(int u,int v,int flow) { 42 e[le].u=u; 43 e[le].v=v; 44 e[le].flow=flow; 45 e[le].next=head[u]; 46 head[u]=le++; 47 e[le].u=v; 48 e[le].v=u; 49 e[le].flow=0; 50 e[le].next=head[v]; 51 head[v]=le++; 52 } 53 int solve(int s,int t) { 54 bfs(s,t); 55 res=top=0; 56 for(i=0;i<=n;i++) cur[i]=head[i]; 57 int u=s; 58 while(dep[s]<n) { 59 if(u==t) { 60 int temp=inf; 61 for(i=0; i<top; i++) 62 if(temp>e[S[i]].flow) { 63 temp=e[S[i]].flow; 64 inser=i; 65 } 66 for(i=0; i<top; i++) { 67 e[S[i]].flow-=temp; 68 e[S[i]^1].flow+=temp; 69 } 70 res+=temp; 71 top=inser; 72 u=e[S[top]].u; 73 } 74 if(u!=t&&!gap[dep[u]-1]) break; 75 for(i=cur[u]; ~i; i=e[i].next) 76 if(e[i].flow&&dep[u]==dep[e[i].v]+1) 77 break; 78 if(~i) { 79 cur[u]=i; 80 S[top++]=i; 81 u=e[i].v; 82 } else { 83 int sma=n; 84 for(i=head[u]; ~i; i=e[i].next) { 85 if(!e[i].flow) continue; 86 if(sma>dep[e[i].v]) { 87 sma=dep[e[i].v]; 88 cur[u]=i; 89 } 90 } 91 --gap[dep[u]]; 92 dep[u]=sma+1; 93 ++gap[dep[u]]; 94 if(u!=s) u=e[S[--top]].u; 95 } 96 } 97 return res; 98 } 99 } gx; 100 int n,m,k,suma,sumb,a[M>>1],b[M>>1],mp[M>>1][M>>1]; 101 int solve(){ 102 if(suma!=sumb) return -1; 103 int s=0,t=n+m+1; 104 gx.init(t+1); 105 for(int i=1;i<=n;i++){ 106 for(int j=1;j<=m;j++){ 107 gx.add(i,j+n,k); 108 } 109 } 110 for(int i=1;i<=n;i++){ 111 gx.add(s,i,a[i]); 112 } 113 for(int i=1;i<=m;i++){ 114 gx.add(i+n,t,b[i]); 115 } 116 if(gx.solve(s,t)!=suma) return -1; 117 int eid=1; 118 for(int i=1;i<=n;i++){ 119 for(int j=1;j<=m;j++,eid+=2){ 120 mp[i][j]=gx.e[eid].flow; 121 } 122 } 123 bool ok=false; //李队随机法过 124 if(n!=1&&m!=1){ 125 for(int t=1; t<=100; t++) { //随机100次就能找到 数据不强? 126 int i=rand()%(n-1)+1; 127 int j=rand()%(m-1)+1; 128 int ii=rand()%(n-i)+1+i; 129 int jj=rand()%(m-j)+1+j; 130 int lu=mp[i][j]; 131 int ld=mp[ii][j]; 132 int ru=mp[i][jj]; 133 int rd=mp[ii][jj]; 134 if(lu>0&&rd>0&&ld<k&&ru<k)ok=true; 135 if(lu<k&&rd<k&&ld>0&&ru>0)ok=true; 136 if(ok)break; 137 } 138 } 139 if(ok) return 0; 140 return 1; 141 } 142 int main(){ 143 while(~scanf("%d%d%d",&n,&m,&k)){ 144 suma=sumb=0; 145 for(int i=1;i<=n;i++){ 146 scanf("%d",&a[i]); 147 suma+=a[i]; 148 } 149 for(int i=1;i<=m;i++){ 150 scanf("%d",&b[i]); 151 sumb+=b[i]; 152 } 153 int ans=solve(); 154 if(ans==-1){ 155 puts("Impossible"); 156 } 157 else if(!ans){ 158 puts("Not Unique"); 159 } 160 else{ 161 puts("Unique"); 162 for(int i=1;i<=n;i++){ 163 for(int j=1;j<=m;j++){ 164 if(j>1) printf(" "); 165 printf("%d",mp[i][j]); 166 } 167 puts(""); 168 } 169 } 170 } 171 }
从源点向行连容量为行总和的边,从列向汇点连容量为列总和的边,从行->列连容量为K的边。这样跑出最大流,如果是满流就有解。判断多解就是判断最大流是否有多解。在残留网络中,如果能找到一个环,那么流量就可以从这个环绕一圈,而不改变最大流。这个dfs一下就好了。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<queue> 5 #define mt(a,b) memset(a,b,sizeof(a)) 6 using namespace std; 7 const int inf=0x7fffffff; 8 const int M=1024; 9 class Sap { //最大流sap算法O(V*E^2) 10 int n,dep[M],gap[M],cur[M],S[M],res,top,i,inser; 11 queue<int> q; 12 void bfs(int s,int t) { 13 mt(dep,-1); 14 mt(gap,0); 15 while(!q.empty()) q.pop(); 16 gap[0]=1; 17 dep[t]=0; 18 q.push(t); 19 while(!q.empty()) { 20 int u=q.front(); 21 q.pop(); 22 for(int i=head[u]; ~i; i=e[i].next) { 23 int v=e[i].v; 24 if(dep[v]!=-1) continue; 25 q.push(v); 26 dep[v]=dep[u]+1; 27 ++gap[dep[v]]; 28 } 29 } 30 } 31 public: 32 struct E { 33 int u,v,next,flow; 34 } e[M*M]; 35 int le,head[M]; 36 void init(int tn) { 37 n=tn; 38 le=0; 39 mt(head,-1); 40 } 41 void add(int u,int v,int flow) { 42 e[le].u=u; 43 e[le].v=v; 44 e[le].flow=flow; 45 e[le].next=head[u]; 46 head[u]=le++; 47 e[le].u=v; 48 e[le].v=u; 49 e[le].flow=0; 50 e[le].next=head[v]; 51 head[v]=le++; 52 } 53 int solve(int s,int t) { 54 bfs(s,t); 55 res=top=0; 56 for(i=0;i<=n;i++) cur[i]=head[i]; 57 int u=s; 58 while(dep[s]<n) { 59 if(u==t) { 60 int temp=inf; 61 for(i=0; i<top; i++) 62 if(temp>e[S[i]].flow) { 63 temp=e[S[i]].flow; 64 inser=i; 65 } 66 for(i=0; i<top; i++) { 67 e[S[i]].flow-=temp; 68 e[S[i]^1].flow+=temp; 69 } 70 res+=temp; 71 top=inser; 72 u=e[S[top]].u; 73 } 74 if(u!=t&&!gap[dep[u]-1]) break; 75 for(i=cur[u]; ~i; i=e[i].next) 76 if(e[i].flow&&dep[u]==dep[e[i].v]+1) 77 break; 78 if(~i) { 79 cur[u]=i; 80 S[top++]=i; 81 u=e[i].v; 82 } else { 83 int sma=n; 84 for(i=head[u]; ~i; i=e[i].next) { 85 if(!e[i].flow) continue; 86 if(sma>dep[e[i].v]) { 87 sma=dep[e[i].v]; 88 cur[u]=i; 89 } 90 } 91 --gap[dep[u]]; 92 dep[u]=sma+1; 93 ++gap[dep[u]]; 94 if(u!=s) u=e[S[--top]].u; 95 } 96 } 97 return res; 98 } 99 } gx; 100 int n,m,k,suma,sumb,a[M>>1],b[M>>1],mp[M>>1][M>>1]; 101 bool vis[M]; 102 bool dfs(int u,int fa){ 103 for(int i=gx.head[u];~i;i=gx.e[i].next){ 104 int w=gx.e[i].flow; 105 if(w==0) continue; 106 int v=gx.e[i].v; 107 if(v!=fa){ 108 if(vis[v]) return true; 109 vis[v]=true; 110 if(dfs(v,u)) return true; 111 vis[v]=false; 112 } 113 } 114 return false; 115 } 116 int solve(){ 117 if(suma!=sumb) return -1; 118 int s=0,t=n+m+1; 119 gx.init(t+1); 120 for(int i=1;i<=n;i++){ 121 for(int j=1;j<=m;j++){ 122 gx.add(i,j+n,k); 123 } 124 } 125 for(int i=1;i<=n;i++){ 126 gx.add(s,i,a[i]); 127 } 128 for(int i=1;i<=m;i++){ 129 gx.add(i+n,t,b[i]); 130 } 131 if(gx.solve(s,t)!=suma) return -1; 132 int eid=1; 133 for(int i=1;i<=n;i++){ 134 for(int j=1;j<=m;j++,eid+=2){ 135 mp[i][j]=gx.e[eid].flow; 136 } 137 } 138 mt(vis,0); 139 for(int i=1;i<=n;i++){ 140 if(dfs(i,-1)){ 141 return 0; 142 } 143 } 144 return 1; 145 } 146 int main(){ 147 while(~scanf("%d%d%d",&n,&m,&k)){ 148 suma=sumb=0; 149 for(int i=1;i<=n;i++){ 150 scanf("%d",&a[i]); 151 suma+=a[i]; 152 } 153 for(int i=1;i<=m;i++){ 154 scanf("%d",&b[i]); 155 sumb+=b[i]; 156 } 157 int ans=solve(); 158 if(ans==-1){ 159 puts("Impossible"); 160 } 161 else if(!ans){ 162 puts("Not Unique"); 163 } 164 else{ 165 puts("Unique"); 166 for(int i=1;i<=n;i++){ 167 for(int j=1;j<=m;j++){ 168 if(j>1) printf(" "); 169 printf("%d",mp[i][j]); 170 } 171 puts(""); 172 } 173 } 174 } 175 }
end