D-Grid Components
在一个100*100的网格图上染色,问黑格四连通块的个数为A,白格四连通块的个数为B的一种构造方案?(A,B<=500)
将整个平面分成50*100的两部分,分别以黑白为背景,一块背景算一个连通块,然后在一种背景上用另一种颜色上去点彩,连通块大小为1,无八连通。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int a,b; 4 int main() 5 { 6 scanf("%d%d",&a,&b); 7 a--;b--; 8 puts("100 100"); 9 for (int i=1;i<=50;i++) 10 { 11 for (int j=1;j<=100;j++) 12 if (i%2==0&&j%2==0&&a>0) printf("."),a--; 13 else printf("#"); 14 puts(""); 15 } 16 for (int i=1;i<=50;i++) 17 { 18 for (int j=1;j<=100;j++) 19 if (i%2==0&&j%2==0&&b>0) printf("#"),b--; 20 else printf("."); 21 puts(""); 22 } 23 return 0; 24 }
E-Bichrome Spanning Tree
在一张图上黑白染色,使得所有同时包含有黑白边的最小生成树权值恰好为X。问有多少种染色方法?
讨论一下嘛,设原树的mst值为sum。若sum>X,答案为0。
若sum=X,那么设原树所有最小生成树的边集为S,只要其中不全为同色边,一定存在一棵黑白mst,答案为(2^(m-|S|))*(2^|S|-2)。
若sum<X。那么S中的边一定都是同色边。考虑加入一条异色边,包含这条异色边的mst一定只包含这条异色边。换边求mst法。定义w[i]为在mst上强加i这条边的贡献=该边权-链上最大。当sum+w[i]<X时,必须同色。当sum+w[i]=X时,至少有一条边要和之前的同色块不同色,有z个。当sum+w[i]>X时,随便染色,有t个。答案为(2^t)*((2^z)-1)*2。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1005; 5 const int mod=1e9+7; 6 struct node{int u,v,w;}e[N<<1]; 7 struct _node{int to,next,w;}num[N<<1]; 8 int cnt,head[N],n,m,fa[N][13],dep[N],Max[N][13],f[N],tag[N<<1],t1,t2; 9 ll sum,x; 10 bool operator < (const node &A,const node &B) {return A.w<B.w;} 11 int find(int x) {return x==f[x]?x:f[x]=find(f[x]);} 12 void add(int x,int y,int w) 13 {num[++cnt].to=y;num[cnt].next=head[x];num[cnt].w=w;head[x]=cnt;} 14 void mst() 15 { 16 sort(e+1,e+m+1); 17 for (int i=1;i<=n;i++) f[i]=i; 18 for (int i=1;i<=m;i++) 19 if (find(e[i].u)!=find(e[i].v)) 20 sum+=e[i].w,f[find(e[i].u)]=find(e[i].v),tag[i]=1,add(e[i].u,e[i].v,e[i].w),add(e[i].v,e[i].u,e[i].w); 21 } 22 void dfs(int x) 23 { 24 for (int i=head[x];i;i=num[i].next) 25 if (num[i].to!=fa[x][0]) 26 { 27 dep[num[i].to]=dep[x]+1; 28 fa[num[i].to][0]=x; 29 Max[num[i].to][0]=num[i].w; 30 dfs(num[i].to); 31 } 32 } 33 void init() 34 { 35 for (int j=1;j<=12;j++) 36 for (int i=1;i<=n;i++) 37 fa[i][j]=fa[fa[i][j-1]][j-1],Max[i][j]=max(Max[i][j-1],Max[fa[i][j-1]][j-1]); 38 } 39 int jump(int x,int y) 40 { 41 if (dep[x]<dep[y]) swap(x,y); 42 int del=dep[x]-dep[y],ans=0; 43 for (int i=0;i<=12;i++) 44 if (del&(1<<i)) ans=max(ans,Max[x][i]),x=fa[x][i]; 45 if (x==y) return ans; 46 for (int i=12;i>=0;i--) 47 if (fa[x][i]!=fa[y][i]) ans=max(ans,Max[x][i]),ans=max(ans,Max[y][i]),x=fa[x][i],y=fa[y][i]; 48 return max(max(ans,Max[x][0]),Max[y][0]);//一不小心把Max写成fa了! 49 } 50 int ksm(int x,int y) 51 { 52 int res=1; 53 for (;y;x=(ll)x*x%mod,y>>=1) 54 if (y&1) res=(ll)res*x%mod; 55 return res; 56 } 57 int main() 58 { 59 scanf("%d%d",&n,&m); 60 scanf("%lld",&x); 61 for (int i=1;i<=m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); 62 mst(); 63 if (sum>x) return puts("0"),0; 64 else{ 65 dfs(1);init(); 66 for (int i=1;i<=m;i++) 67 if (!tag[i]) 68 { 69 int t=jump(e[i].u,e[i].v); 70 if (e[i].w-t==x-sum) t1++; 71 else if (e[i].w-t>x-sum) t2++; 72 } 73 if (x==sum) printf("%lld\n",((ll)ksm(2,t2)*(ksm(2,t1+n-1)-2+mod)%mod)%mod); 74 else printf("%lld\n",(ll)ksm(2,t2)*(ksm(2,t1)-1+mod)%mod*2%mod); 75 } 76 return 0; 77 }
F-Dark Horse
一共有2^n个数。每次相邻两个pk。给你一个数组A,如果x=1,y=Ai,那么y赢,否则1赢。其他的都是较小的赢。问最后剩下的数为1的方案数?n<=16。
固定1在第一个位置,其他情况都是可以转换的,最后*2^n。那么1最后剩下来当且仅当[2,2],[3,4],[5,8],[9,16],...这些区间中的最小值都不是A中元素。
可以容斥。dp[i][j]表示放进了i个数,j表示有哪几个区间的最小值已经被确定。
从大到小枚举元素:1.该元素不作为某个区间的最小值,dp[i][j]<-dp[i-1][j]。2.该元素成为k区间的最小值,用比当前元素大的未被使用的元素填满该区间。
dp[i][j|(1<<k)]<-dp[i][j]*C(Max-a[i]-j,(1<<k)-1)*jc[1<<k].那么dp[n][i]*jc[(1<<n)-i-1]就是至少有popcount(i)个区间最小值为A中元素,容斥。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int mod=1e9+7; 4 typedef long long ll; 5 const int N=66666; 6 int jc[N],inv[N],n,m,ans,Max,num,dp[20][N],a[N]; 7 void up(int &x,int y) {x=((ll)x+y)%mod;} 8 int calc(int x){int res=0;while (x) x-=(x&(-x)),res++;return res;} 9 void init() 10 { 11 jc[0]=jc[1]=inv[0]=inv[1]=1; 12 for (int i=2;i<Max;i++) jc[i]=(ll)jc[i-1]*i%mod,inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod; 13 for (int i=2;i<Max;i++) inv[i]=(ll)inv[i]*inv[i-1]%mod; 14 } 15 int C(int n,int m) 16 { 17 if (n<m) return 0; 18 return (ll)jc[n]*inv[m]%mod*inv[n-m]%mod; 19 } 20 int main() 21 { 22 scanf("%d%d",&n,&m); 23 for (int i=1;i<=m;i++) scanf("%d",&a[m-i+1]);//从大到小 24 Max=1<<n;init(); 25 dp[0][0]=1; 26 for (int i=1;i<=m;i++) 27 for (int j=0;j<Max;j++) 28 if (dp[i-1][j]) 29 { 30 up(dp[i][j],dp[i-1][j]); 31 for (int k=0;k<n;k++) 32 if (!(j&(1<<k))) 33 up(dp[i][j|(1<<k)],(ll)C(Max-a[i]-j,(1<<k)-1)*jc[1<<k]%mod*dp[i-1][j]%mod); 34 } 35 for (int i=0;i<Max;i++) 36 { 37 num=calc(i); 38 if (num&1) up(ans,(mod-(ll)dp[m][i]*jc[Max-i-1]%mod)%mod); 39 else up(ans,(ll)dp[m][i]*jc[Max-i-1]%mod); 40 } 41 printf("%lld\n",(ll)ans*Max%mod); 42 return 0; 43 }