ZJOI2011 Day1 ( bzoj2227~2229 ) 题解

来源:互联网 发布:淘宝购买家具退货 编辑:程序博客网 时间:2024/05/16 16:24
bzoj2227 看电影:

先打个暴力,然后找规律。得到答案:ans=(k+1)n-1*(k-n+1)/kn

正解:http://blog.lightning34.cn/?p=166

注意到答案很大,又由于n,k<=200,将k+1,k-n+1,k分解质因数,然后高精乘就可以了

 

暴力代码:

 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 #define ll long long 7 #define N 210 8 ll x,y,g; 9 int i,j,k,n,m,T;10 bool b[N];11 inline ll Gcd(ll x,ll y){12     if(y==0)return x;13     return Gcd(y,x%y);14 }15 inline ll Pow(int x,int y){16     if(y==0)return 1;17     ll Ans=Pow(x,y>>1);18     Ans*=Ans;19     if(y&1)return Ans*x;return Ans;20 }21 inline ll Dfs(int x){22     if(x==n+1)return 1;23     ll Ans=0;24     int j=0;25     for(int i=1;i<=k;i++)26     if(!b[i]){27         b[i]=1;28         Ans+=Dfs(x+1)*(i-j);29         b[j=i]=0;30     }31     return Ans;32 }33 int main()34 {35     for(n=1;n<=9;n++)36     for(k=n;k<=9;k++){37         cout<<n<<" "<<k<<" ";38         memset(b,0,sizeof(b));39         x=Dfs(1);y=Pow(k,n);40         printf("%lld %lld\n",x,y);41     } 42 }43 44 bzoj2227(暴力)
bzoj2227(暴力)

AC代码:

 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 #define N 210 7 #define M 510 8 int i,T,j,k,n,m,p[N][N],P[N],Num,ans[N],a2[N],s,a[M],l,x; 9 inline void C(int x){10     if(l==0){11         a[l=1]=x;12         for(l++;a[l];)a[l+1]+=a[l]/10,a[l++]%=10;l--;13         return;14     }15     for(int i=1;i<=l;i++)a[i]*=x;16     for(int i=1;i<=l;i++)a[i+1]+=a[i]/10,a[i]%=10;17     for(l++;a[l];)a[l+1]+=a[l]/10,a[l++]%=10;l--;18 }19 int main()20 {21     for(i=2;i<N;i++){22         s=sqrt((double)i);23         for(j=2;j<=s;j++)24         if(i%j==0)break;25         if(j>s)P[++Num]=i;26     }27     for(i=1;i<N;i++){28         x=i;29         for(j=1;j<=Num;j++)30         while(x%P[j]==0)p[i][P[j]]++,x/=P[j];31     }32     scanf("%d",&T);33     while(T--){34         scanf("%d%d",&n,&k);35         if(n>k){puts("0 1");continue;}36         memset(a,0,sizeof(a));l=0;37         memset(ans,0,sizeof(ans));38         memset(a2,0,sizeof(a2));39         for(i=1;i<=k+1;i++)ans[i]=p[k+1][i]*(n-1);40         if(k-n)for(i=1;i<=k-n+1;i++)ans[i]+=p[k-n+1][i];41         if(k>1)for(i=1;i<=k;i++)42         a2[i]=p[k][i]*n-ans[i],ans[i]-=p[k][i]*n;43         for(i=1;i<N;i++)44         for(i=1;i<N;i++)45         for(j=1;j<=ans[i];j++)C(i);                46         if(!l)putchar('1');47         for(i=l;i;i--)putchar(a[i]+48);putchar(' ');48         memset(a,0,sizeof(a));l=0;49         for(i=1;i<N;i++)50         for(j=1;j<=a2[i];j++)C(i);51         if(!l)putchar('1');52         for(i=l;i;i--)putchar(a[i]+48);putchar('\n');53     }54     return 0;55 }
bzoj2227

 

bzoj2228 礼物:

枚举将哪一面作为底面。枚举每一层,令f[i][j][k]表示在第k层右下角在(i,j)时最大的正方形边长,得到:

f[i][j][k]=min(f[i][j-1][k],f[i-1][j][k],f[i-1][j-1][k])+1

枚举i,j,那么问题就转化为求序列的区间最小值*区间长度的最大值

枚举每个数,用单调栈求出它作为最小值时向左、右最多延伸的长度即可。

时间复杂度O(n3)

 

代码:

 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 using namespace std; 5 #define N 160 6 int i,j,k,n,m,f[N][N][N],p,q,r,b[N],Q[N],t,Ans; 7 bool a[N][N][N],A[N][N][N]; 8 char c[N]; 9 inline int _Max(int x,int y){return x>y?x:y;}10 inline int _Min(int x,int y){return x<y?x:y;}11 inline void Work(){12     for(k=1;k<=r;k++)13     for(i=1;i<=p;i++)14     for(j=1;j<=q;j++)15     if(a[i][j][k])f[i][j][k]=0;else f[i][j][k]=_Min(_Min(f[i-1][j][k],f[i][j-1][k]),f[i-1][j-1][k])+1;16     for(i=1;i<=p;i++)17     for(j=1;j<=q;j++){18         f[i][j][0]=f[i][j][r+1]=-1;19         for(Q[t=1]=0,k=1;k<=r;k++){20             while(f[i][j][Q[t]]>=f[i][j][k])t--;21             b[k]=Q[t]+1;Q[++t]=k;22         }23         for(Q[t=1]=r+1,k=r;k>=1;k--){24             while(f[i][j][Q[t]]>=f[i][j][k])t--;25             Ans=_Max(Ans,f[i][j][k]*(Q[t]-b[k]));Q[++t]=k;26         }27     }28 }29 int main()30 {31     scanf("%d%d%d",&p,&q,&r);32     for(i=1;i<=q;i++)33     for(j=1;j<=p;j++){34         scanf("%s",c+1);35         for(k=1;k<=r;k++)if(c[k]=='P')A[j][i][k]=a[j][i][k]=1;36     }37     for(Work(),i=1;i<=p;i++)38     for(j=1;j<=q;j++)39     for(k=1;k<=r;k++)40     a[i][r-k+1][j]=A[i][j][k];41     for(swap(q,r),Work(),swap(q,r),i=1;i<=p;i++)    42     for(j=1;j<=q;j++)43     for(k=1;k<=r;k++)44     a[k][j][p-i+1]=A[i][j][k];45     swap(p,r);Work();46     printf("%d",Ans<<2);47     return 0;48 }
bzoj2228

 

bzoj2229 最小割:

有一个结论:一个n个点的图最多只有n-1个最小割。

那么我们先求出(s,t)的最小割(X,Y),对于i∈X,j∈Y,更新ans[i][j],再对X,Y中的点分别进行前面的步骤就可以了。

 

代码:

 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 #define N 160 6 #define M 3010 7 #define INF 2147483647 8 struct Edge{ 9     int c,t,nx;10 }e[M<<1];11 int Num,i,h[N],Cur[N],j,k,S[N],q[N],l,r,n,m,a[N],A[N],Ans[N][N],x,y,z,_Ans,T,Q;12 bool b[N],B[N];13 inline int _Min(int x,int y){return x<y?x:y;}14 inline void Add(int x,int y,int z){e[++Num].t=y;e[Num].c=z;e[Num].nx=h[x];h[x]=Num;}15 inline bool Bfs(int s,int t){16     memset(b,0,sizeof(b));17     b[s]=1;l=0;q[r=1]=s;S[s]=0;18     while(++l<=r){19         for(int i=h[q[l]];i;i=e[i].nx)20         if(e[i].c&&!b[e[i].t])q[++r]=e[i].t,S[e[i].t]=S[q[l]]+1,b[e[i].t]=1;21     }22     return b[t];23 }24 inline int Dfs(int x,int a,int t){25     if(a==0||x==t)return a;26     int f,F=0;27     for(int& i=Cur[x];i;i=e[i].nx)28     if(S[e[i].t]==S[x]+1&&e[i].c&&(f=Dfs(e[i].t,_Min(a-F,e[i].c),t))){29         e[i].c-=f;e[i^1].c+=f;F+=f;30         if(a==F)break;31     }32     return F;33 }34 inline int Max_flow(int s,int t){35     int Ans=0;36     while(Bfs(s,t)){37         for(int i=1;i<=n;i++)Cur[i]=h[i];38         Ans+=Dfs(s,INF,t);39     }40     return Ans;41 }42 inline void Dfs(int x){43     B[x]=1;44     for(int i=h[x];i;i=e[i].nx)45     if(e[i].c&&!B[e[i].t])Dfs(e[i].t);46 }47 inline void Divide(int l,int r){48     if(l==r)return;49     for(int i=2;i<=Num;i+=2)e[i].c=e[i+1].c=(e[i].c+e[i+1].c)>>1;50     int Mf=Max_flow(a[l],a[r]);51     memset(B,0,sizeof(B));52     Dfs(a[l]);53     for(int i=1;i<=n;i++)54     if(B[i])for(int j=1;j<=n;j++)55     if(!B[j])Ans[i][j]=Ans[j][i]=_Min(Ans[i][j],Mf);56     int l1=l,l2=r;57     for(int i=l;i<=r;i++)58     if(B[a[i]])A[l1++]=a[i];else A[l2--]=a[i];59     for(int i=1;i<=n;i++)a[i]=A[i];60     Divide(l,l1-1);Divide(l2+1,r);61 }62 int main()63 {64     scanf("%d",&T);65     while(T--){66         scanf("%d%d",&n,&m);67         for(Num=1,memset(h,0,sizeof(h)),i=1;i<=m;i++)scanf("%d%d%d",&x,&y,&z),Add(x,y,z),Add(y,x,z);68         for(i=1;i<=n;i++)a[i]=i;69         memset(Ans,127,sizeof(Ans));70         Divide(1,n);71         scanf("%d",&Q);72         while(Q--){73             scanf("%d",&x);74             for(_Ans=0,i=1;i<=n;i++)75             for(j=i+1;j<=n;j++)76             if(Ans[i][j]<=x)_Ans++;77             printf("%d\n",_Ans);78         }79         putchar('\n');80     }81 }
bzoj2229

 

概率就是可行方案除以所有方案。

所有方案就是 knkn

考虑可行方案,如果加上一个座位使得所有的位置连成环的话,方案数就是 (k+1)n(k+1)n,另外由于是环,有重复的情况,所以要除以 k+1k+1

然后再断开,只要是空位的都可以断开,所以断开的方案数为 kn+1k−n+1

所以最后的可行方案数为 (kn+1)(k+1)n1(k−n+1)(k+1)n−1

答案可以质因数分解之后高精度求。

原创粉丝点击