我好菜啊。。。數學不會數據結構不會博弈不會圖論也不會,現在構造也不會了。。。
今天看似來了倆構造。然而一個是憑空想象的結論題(好難證。。。)還有一個是提答
於是我就憑空想象了,然而我菜所以猜錯了,然後炸了,倒是也比多數人多了$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$