[考试反思]0515省选模拟97:构造
我好菜啊。。。数学不会数据结构不会博弈不会图论也不会,现在构造也不会了。。。
今天看似来了俩构造。然而一个是凭空想象的结论题(好难证。。。)还有一个是提答
于是我就凭空想象了,然而我菜所以猜错了,然后炸了,倒是也比多数人多了$10pts$
于是我就去提答了,然而这道题如果想认真写的话分数都不低,然后拿了个大概大众分就结束了
然后最后还有点时间写$T2$暴力的$20pts$来着 ,这时候突然钻出来了一个牛爷爷(窗口抖动)问我提答怎么交
我懵了(为啥不直接问教练),然后反正我最后暴力没交上去,我就无了
(牛爷爷天天$rk1$啊,这不是我说的)
(话说以前提答题都是怎么交上去的。。?)
T1:心的旋律(circle)
大意:构造一个两侧都有$n$个点的二分图,要求$k = \sum\limits_{A \subseteq [1,n]} [ |f(A)|<|A| ] $。$f(A)$指$A$集合点的所有出边到达的点的并集。$n \le 32,k \le 2^n$
首先$<$的限制比较麻烦,我们把条件改成大于等于(同时把$k$也改成$2^n-k$)。把$\sum$那个式子叫做一个图的 对应值 。
首先如果$k=0$,由于空集的存在,无解。
然后我们只要猜到:可以构造一种图满足左侧点连的右侧点集合为包含关系,且如果存在大小为$x$的集合就存在大小为$x-1$的集合。
为了方便我们强制集合就是一个$[1,size_i]$的前缀。同时把所有左侧点按照$size$排序。
然后这个图就相当于一个单调不减的$size$序列且满足$0 \le size_{i-1} \le size_i \le 1$。
我们设所有$size_i - size_{i-1} =1$的位置$i$我们把它丢进一个$B$集合里。设$m=|B|$
那么这个图的对应值就是:
$\sum\limits_{i=1}^{m} \binom{n}{i} - \sum\limits_{i=1}^{m} \binom{B_i-1}{i}$
需证:
1)对于任意$m$,大小为$m+1$的$B$集合对应的值比大小为$m$的大(设这个问题为$proof(n,m)$)
也就是说,大小为$m+1$的$B$集合对应的最小值 比 大小为$m$的$B$集合的对应最大值 要大。
我们作差一下,减号前面的部分抵消只剩下一项$\binom{n}{m+1}$
大小为$m+1$的集合要尽量小,也就是后面减去的集合要尽量大,那么就满足$B_i=n+i-(m+1)$
然后后面的那堆组合数就是$\sum\limits_{i=1}^{m+1} \binom{n+i-m-2}{i}$
这是一条斜线上的组合数求和,也就相当于是一列,直接组合恒等式干掉,得到这玩意就是$\binom{n}{m+1}-1$
所以$minval(m+1)-maxval(m)=1$
2)对于$m$相同时,$B$对应二进制下较大的,对应值较小
也就是说,两个$B$对位比较,第一次错开的位置,两数中较大者,对应值更小。
于是我们就直接从这个第一次错开的位置开始考虑,假如更高位上已经有$x$个$1$然后当前位是$M$。
我们发现我们需要证明的就是$proof(M-1,m-x-1)$。所以也已经证出来了。
3)每种$B$集合都与一个$0< \le 2^n$对应值一一对应。
上面的证明中,我们已经知道了在刚才的比较关系中,$min-max=1$也就是元素是两两相邻,$B$为空时显然是$1$。故得证。
综上,$B$集合写成二进制数后,第一关键字为1$的个数$第二关键字为权值排序后,排名为$i$的数对应值就是$i$(排名从$1$开始)
然后就逐位确定地构造一下就行了。枚举$1$的个数再枚举每一位填啥。
T2:幻化成风(count)
不会。有空回来补$60pts$暴力。营养丰富。
T3:大家佛(cut)
大意:提答。给定$n \times m$权值随机的矩阵,要求你把它分成$k$个联通块,使得块和最大值-块和最小值尽量小。
给出$84pts$的生成代码。
1 #include<bits/stdc++.h> 2 using namespace std; 3 char input[10],output[10]; 4 int n,m,w,k,mtx[1005][1005];long long tot; 5 int pre[1000],ans[1005][1005]; 6 int main(){ 7 for(int test=1;test<=10;++test){ 8 sprintf(input,"cut%d.in",test);freopen(input,"r",stdin); 9 sprintf(output,"cut%d.out",test);freopen(output,"w",stdout); 10 11 scanf("%d%d%d%d",&n,&m,&k,&w);tot=0; 12 for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)scanf("%d",&mtx[i][j]),tot+=mtx[i][j]; 13 14 if(test==1){ 15 puts("1 1 1 1 1 1 1 1 1 1"); 16 puts("1 1 1 1 1 1 1 1 1 1"); 17 puts("2 2 2 2 2 2 2 1 1 2"); 18 puts("2 2 2 2 2 2 2 2 2 2"); 19 puts("3 3 3 3 3 2 2 2 2 2"); 20 puts("3 3 3 3 3 3 3 3 3 3"); 21 puts("4 4 4 4 4 4 3 3 3 3"); 22 puts("4 4 4 4 4 4 4 4 4 4"); 23 puts("4 5 4 5 5 5 5 5 5 5"); 24 puts("5 5 5 5 5 5 5 5 5 5"); 25 } 26 if(test==2){ 27 puts("1 1 1 1 3"); 28 puts("1 2 2 1 3"); 29 puts("1 2 2 1 3"); 30 puts("1 2 2 2 3"); 31 puts("3 3 3 3 3"); 32 } 33 if(test==3){ 34 puts("1 1 1 1 1"); 35 puts("2 2 2 1 1"); 36 puts("2 2 2 2 1"); 37 puts("3 2 3 3 3"); 38 puts("3 3 3 3 3"); 39 } 40 if(test==4){ 41 int p=1,tot=0,co=1; 42 while(p<=m){ 43 if(tot+mtx[1][p]+mtx[2][p]+mtx[3][p]<=60)ans[1][p]=ans[2][p]=ans[3][p]=co,tot+=mtx[1][p]+mtx[2][p]+mtx[3][p]; 44 else if(tot+mtx[1][p]+mtx[2][p]<=60)ans[1][p]=ans[2][p]=co,ans[3][p]=++co,tot=mtx[3][p]; 45 else if(tot+mtx[1][p]+mtx[3][p]<=60)ans[1][p]=ans[3][p]=co,ans[2][p]=++co,tot=mtx[2][p]; 46 else if(tot+mtx[2][p]+mtx[3][p]<=60)ans[2][p]=ans[3][p]=co,ans[1][p]=++co,tot=mtx[1][p]; 47 else if(tot+mtx[1][p]<=60)ans[1][p]=co,ans[2][p]=ans[3][p]=++co,tot=mtx[2][p]+mtx[3][p]; 48 else if(tot+mtx[2][p]<=60)ans[2][p]=co,ans[1][p]=ans[3][p]=++co,tot=mtx[1][p]+mtx[3][p]; 49 else ans[1][p]=ans[2][p]=ans[3][p]=++co,tot=mtx[1][p]+mtx[2][p]+mtx[3][p]; 50 p++; 51 } 52 for(int i=1;i<=n;++i,puts(""))for(int j=1;j<=m;++j)printf("%d ",ans[i][j]),ans[i][j]=0; 53 } 54 55 if(test==5){ 56 for(int x=1;x<=k;++x){ 57 int tg=tot/k+(x<=tot%k); 58 for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)if(!ans[i][j]&&tg>=mtx[i][j])ans[i][j]=x,tg-=mtx[i][j]; 59 } 60 for(int i=1;i<=n;++i,puts(""))for(int j=1;j<=m;++j)printf("%d ",ans[i][j]); 61 } 62 63 if(test>=6&&test!=9){ 64 for(int i=1;i<=k;++i)pre[i]=pre[i-1]+n*m/k+(i<=n*m%k); 65 pre[k+1]=pre[k]+1; 66 int tot=0,x=1,y=1,p=1; 67 while(x<=n){ 68 tot++; 69 if(tot>pre[p])p++; 70 ans[x][y]=p; 71 if(x&1){if(y==m)x++;else y++;} 72 else{if(y==1)x++;else y--;} 73 } 74 for(int i=1;i<=n;++i,puts(""))for(int j=1;j<=m;++j)printf("%d ",ans[i][j]),ans[i][j]=0; 75 } 76 77 if(test==9){ 78 for(int i=1;i<=n;++i,puts(""))for(int j=1;j<=m;++j)printf("%d ",(j-1)/(n/k)+1); 79 } 80 81 } 82 }
对于较大的数据,可以蛇行走位遍历整个矩阵然后按照权值砍蛇。可以优化到$92pts$