[考試反思]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 }
View Code

對於較大的數據,可以蛇行走位遍歷整個矩陣然後按照權值砍蛇。可以優化到$92pts$

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章