[考试反思]0515省选模拟97:构造

[考试反思]0515省选模拟97:构造

[考试反思]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$的生成代码。

#include<bits/stdc++.h>
using namespace std;
char input[10],output[10];
int n,m,w,k,mtx[1005][1005];long long tot;
int pre[1000],ans[1005][1005];
int main(){
    for(int test=1;test<=10;++test){
        sprintf(input,"cut%d.in",test);freopen(input,"r",stdin);
        sprintf(output,"cut%d.out",test);freopen(output,"w",stdout);
        
        scanf("%d%d%d%d",&n,&m,&k,&w);tot=0;
        for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)scanf("%d",&mtx[i][j]),tot+=mtx[i][j];
        
        if(test==1){
            puts("1 1 1 1 1 1 1 1 1 1");
            puts("1 1 1 1 1 1 1 1 1 1");
            puts("2 2 2 2 2 2 2 1 1 2");
            puts("2 2 2 2 2 2 2 2 2 2");
            puts("3 3 3 3 3 2 2 2 2 2");
            puts("3 3 3 3 3 3 3 3 3 3");
            puts("4 4 4 4 4 4 3 3 3 3");
            puts("4 4 4 4 4 4 4 4 4 4");
            puts("4 5 4 5 5 5 5 5 5 5");
            puts("5 5 5 5 5 5 5 5 5 5");
        }
        if(test==2){
            puts("1 1 1 1 3");
            puts("1 2 2 1 3");
            puts("1 2 2 1 3");
            puts("1 2 2 2 3");
            puts("3 3 3 3 3");
        }
        if(test==3){
            puts("1 1 1 1 1");
            puts("2 2 2 1 1");
            puts("2 2 2 2 1");
            puts("3 2 3 3 3");
            puts("3 3 3 3 3");
        }
        if(test==4){
            int p=1,tot=0,co=1;
            while(p<=m){
                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];
                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];
                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];
                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];
                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];
                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];
                else ans[1][p]=ans[2][p]=ans[3][p]=++co,tot=mtx[1][p]+mtx[2][p]+mtx[3][p];
                p++;
            }
            for(int i=1;i<=n;++i,puts(""))for(int j=1;j<=m;++j)printf("%d ",ans[i][j]),ans[i][j]=0;
        }
        
        if(test==5){
            for(int x=1;x<=k;++x){
                int tg=tot/k+(x<=tot%k);
                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];
            }
            for(int i=1;i<=n;++i,puts(""))for(int j=1;j<=m;++j)printf("%d ",ans[i][j]);
        }
        
        if(test>=6&&test!=9){
            for(int i=1;i<=k;++i)pre[i]=pre[i-1]+n*m/k+(i<=n*m%k);
            pre[k+1]=pre[k]+1;
            int tot=0,x=1,y=1,p=1;
            while(x<=n){
                tot++;
                if(tot>pre[p])p++;
                ans[x][y]=p;
                if(x&1){if(y==m)x++;else y++;}
                else{if(y==1)x++;else y--;}
            }
            for(int i=1;i<=n;++i,puts(""))for(int j=1;j<=m;++j)printf("%d ",ans[i][j]),ans[i][j]=0;
        }
        
        if(test==9){
            for(int i=1;i<=n;++i,puts(""))for(int j=1;j<=m;++j)printf("%d ",(j-1)/(n/k)+1);
        }
        
    }
}

对于较大的数据,可以蛇行走位遍历整个矩阵然后按照权值砍蛇。可以优化到$92pts$

相关推荐