2012成都网络赛赛后【缺CHJ】


A Coder (HDU 4288,与Codeforces 85D相同)


应该用线段树写,我是块状链表水过了

 #include<map>
 #include<cstdio>
 #include<cstring>
 #include<algorithm>
 using namespace std;
 
 typedef long long ll;
 const int N=320*320;
 
 struct Query
 {
     char s[5];
     int x;
 }q[N];
 
 int a[N],sz[N],n;
 ll sum[320][5];
 
 int main()
 {
     while(scanf("%d",&n)!=EOF)
     {
         int k=0,block=0;
         while(block*block<n) block++;
         for(int i=0;i<n;i++)
         {
             scanf("%s",q[i].s);
             if(q[i].s[0]!='s') scanf("%d",&q[i].x),a[k++]=q[i].x;
         }
 
         sort(a,a+k);
         k=unique(a,a+k)-a;
         map<int,int>p;
         for(int i=0;i<k;i++) p[a[i]]=i;
         memset(a,0,sizeof(a));
         memset(sz,0,sizeof(sz));
         memset(sum,0,sizeof(sum));
 
         for(int i=0;i<n;i++)
         {
             if(q[i].s[0]!='s')
             {
                 int pos=p[q[i].x],rt=pos/block;
                 int l=rt*block,r=l+block,k=0;
                 a[pos]=q[i].s[0]=='a'?q[i].x:0;
                 memset(sum[rt],0,sizeof(sum[rt]));
                 for(int i=l;i<r;i++) if(a[i]) sum[rt][k++%5]+=a[i];
                 sz[rt]=k;
             }
             else
             {
                 ll ans=0;k=2;
                 for(int i=0;i<block;i++) ans+=sum[i][k],k=(k-sz[i]+50000)%5;
                 printf("%I64d\n",ans);
             }
         }
     }
     return 0;
 }

B Control (HDU 4289)


网络流求最小割,将每个点拆成两个,流量为点权值

 #include<cstdio>
 #include<cstring>
 #include<algorithm>
 using namespace std;
 
 const int inf=0x3f3f3f3f;
 const int N=444,M=88888;
 FlowNetwork sap;
 
 int main()
 {
     int n,m,s,d,u,v;
     while(scanf("%d%d%d%d",&n,&m,&s,&d)!=EOF)
     {
         sap.init();
         for(int i=1; i<=n; i++) scanf("%d",&v),sap.add(i,i+n,v);
         while(m--)
         {
             scanf("%d%d",&u,&v);
             sap.add(u+n,v,inf);
             sap.add(v+n,u,inf);
         }
         printf("%d\n",sap.sap(s,n+d,n*2));
     }
     return 0;
 }

C Counting Formations (HDU 4290)

D A Short problem (HDU 4291)


先求出g(g(g(n)))每一层的循环节

 #include<iostream>
 using namespace std;
 
 int main()
 {
     long long mod=1000000007,a,b,c,cnt;
     for(int i=0;i<3;i++)
     {
         a=0,b=1,cnt=0;
         while(1)
         {
             c=(3*b+a)%mod;
             a=b,b=c;cnt++;
             if(a==0&&b==1) break;
         }
         cout<<cnt<<endl;
         mod=cnt;
     }
     return 0;
 }
 

记循环节为a=222222224,b=183120,c=240.

则g(g(g(n)))%mod=g(g(g(n%c)%b)%a)%mod,再利用矩阵二分算一下即可:

 #include<iostream>
 #include<cstring>
 using namespace std;
 typedef long long ll;
 struct Mat
 {
     int a[2][2];
     Mat(){memset(a,0,sizeof(a));}
     Mat mul(Mat &b,int mod)
     {
         Mat c;
         for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++)
             c.a[i][j]=(c.a[i][j]+(ll)a[i][k]*b.a[k][j])%mod;
         return *this=c;
     }
     Mat cal(int n,int mod)
     {
         Mat b=*this,c;
         c.a[0][0]=c.a[1][1]=1;
         while(n)
         {
             if(n&1) c.mul(b,mod);
             n>>=1;
             b.mul(b,mod);
         }
         return *this=c;
     }
 };
 
 int g(int n,int mod)
 {
     if(n==0) return 0;
     Mat a;
     a.a[0][0]=3;a.a[1][1]=0;
     a.a[0][1]=a.a[1][0]=1;
     a.cal(n-1,mod);
     return a.a[0][0];
 }
 int main()
 {
     ll n;
     while(cin>>n) cout<<g(g(g(n%240,183120),222222224),1000000007)<<endl;
     return 0;
 }


E Food (HDU 4292)


网络流,建s,e,将人拆点,从s到food连边,food到人连边,人到人‘连边,人’到drink连边,drink到e连边,求出最大流即可

 #include<cstdio>
 #include<cstring>
 #include<algorithm>
 using namespace std;
 
 const int inf=0x3f3f3f3f;
 const int N=888,M=222222;
 
 FlowNetwork sap;
 
 char str[N];
 int main()
 {
     int n,f,d;
     while(scanf("%d%d%d",&n,&f,&d)!=EOF)
     {
         sap.init();
         int s=0,e=n*2+f+d+1,x;
         for(int i=1;i<=f;i++) scanf("%d",&x),sap.add(s,i,x);
         for(int i=n*2+f+1;i<e;i++) scanf("%d",&x),sap.add(i,e,x);
         for(int i=f+1;i<=f+n;i++) sap.add(i,i+n,1);
         for(int i=1;i<=n;i++)
         {
             scanf("%s",str);
             for(int j=0;str[j];j++) if(str[j]=='Y') sap.add(j+1,i+f,inf);
         }
         for(int i=1;i<=n;i++)
         {
             scanf("%s",str);
             for(int j=0;str[j];j++) if(str[j]=='Y') sap.add(n+f+i,n*2+f+j+1,inf);
         }
         printf("%d\n",sap.sap(s,e,e-s+1));
     }
     return 0;
 }


F Groups (HDU 4293)

相同的区间算一个,区间权值++,但不能超过区间长度。然后就是N个区间,从中选择若干个区间使得权值之和尽可能大。

dp[i]表示选择最后一个区间以i为右端点时能获得的最大权值。

 #include<map>
 #include<cstdio>
 #include<cstring>
 using namespace std;
 typedef pair<int,int>tp;
 int dp[555];
 int main()
 {
     int n,a,b;
     while(scanf("%d",&n)!=EOF)
     {
         memset(dp,0,sizeof(dp));
         map<tp,int>mp;
         for(int i=0;i<n;i++)
         {
             scanf("%d%d",&a,&b);
             if(a+b+1<=n&&mp[tp(a+1,n-b)]<n-b-a) mp[tp(a+1,n-b)]++;
         }
         for(map<tp,int>::iterator it=mp.begin();it!=mp.end();it++)
             for(int i=0;i<it->first.first;i++)
                 dp[it->first.second]=max(dp[it->first.second],dp[i]+it->second);
         int ans=0;
         for(int i=0;i<=n;i++) ans=max(ans,dp[i]);
         printf("%d\n",ans);
     }
     return 0;
 }


G Multiple (HDU 4294)


①由一个数组成,由抽屉原理可知长度一定不超过n,否则会存在长度为a时与长度为b时对n取模结果相同,即循环节为b-a+1,且循环中存在某个数%n==0

②由两个数组成,一定可以。对任意n,则长度1-n且全为1的数中一定存在两个长度i,j的数对n取模相同,现在用较大的数减去较小的数,则结果为111111000000,由两个数组成。

对于每次计算,只需要用pre[k]指向第一次k=x%n对应的x。现在只要保证第一次搜到k时对应的x最小,那么每次从pre[0]一直找到pre[w]=-1,对应就是答案。

 #include<cstdio>
 #include<cstring>
 #include<algorithm>
 using namespace std;
 const int N=10010;
 int q[N],pre[N],val[N];
 bool vis[N];
 char s[N],ss[N];
 void bfs(int x,int y,int n,int k)
 {
     memset(vis,0,sizeof(vis));
     int low=0,up=-1;
     if(x) q[++up]=x%n,pre[x%n]=-1,val[x%n]=x,vis[x%n]=1;
     q[++up]=y%n,pre[y%n]=-1,val[y%n]=y,vis[y%n]=1;
     while(low<=up)
     {
         int np=q[low++],tmp;
         if(np==0)
         {
             int w=0,len=strlen(s);
             for(int k=0;~k;k=pre[k]) ss[w++]=48+val[k];
             reverse(ss,ss+w);ss[w]=0;
             if(!s[0]||len>w||len==w&&strcmp(ss,s)<0) strcpy(s,ss);
             return;
         }
         if(!vis[tmp=(np*k+x)%n]) q[++up]=tmp,pre[tmp]=np,val[tmp]=x,vis[tmp]=1;
         if(!vis[tmp=(np*k+y)%n]) q[++up]=tmp,pre[tmp]=np,val[tmp]=y,vis[tmp]=1;
     }
     return;
 }
 int main()
 {
     int n,k;
     while(scanf("%d%d",&n,&k)!=EOF)
     {
         s[0]=0;
         for(int i=1;i<k;i++) bfs(i,i,n,k);
         if(!s[0]) for(int i=1;i<k;i++) for(int j=0;j<i;j++) bfs(j,i,n,k);
         puts(s);
     }
     return 0;
 }


H 4 substrings problem (HDU 4295)


I Buildings (HDU 4296)


考虑相连两层a,b(显然不相连的情况相似):

记tot=w[max(a,b)+1]+……+w[top]:

a在b上面:x=pdv[a]=tot-s[a] y=pdv[b]=tot+w[a]-s[b]

b在a上面:u=pdv[b]=tot-s[b] v=pdv[a]=tot+w[b]-s[a]

①s[a]+w[a]>s[b]+w[b],则有y>v>x与y>u,max(y,x)>max(u,v),所以b在a上面的放法更优。

s[a]+w[a]>s[b]+w[b],则有v>y>u与v>x,max(y,x)<max(u,v),所以a在b上面的放法更优。

即将k=s[i]+w[i]最大的放在最下面时总PDV最小,而且最优PDV=(w[1]+w[2]+……+w[n])-k。

 #include<cstdio>
 int main()
 {
     int n,w,s;
     while(scanf("%d",&n)!=EOF)
     {
         long long k=-1,sum=0;
         for(int i=0;i<n;i++) scanf("%d%d",&w,&s),k=w+s>k?w+s:k,sum+=w;
         printf("%I64d\n",sum>k?sum-k:0);
     }
     return 0;
 }
  



J One and One Story (HDU 4297)


你可能感兴趣的:(2012成都网络赛赛后【缺CHJ】)