Scx117
只一眼,便辽阔了时间。

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

 

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

 

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

 

posted on 2018-06-12 20:57  Scx117  阅读(291)  评论(0编辑  收藏  举报