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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 李队随机法选点测试,随机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 }
View Code

 从源点向行连容量为行总和的边,从列向汇点连容量为列总和的边,从行->列连容量为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 }
View Code

 

 

 

 

 

 

 

end

posted on 2014-07-29 20:03  gaolzzxin  阅读(254)  评论(0编辑  收藏  举报