1. 程式人生 > >gym101964G Matrix Queries seerc2018g題 數學歸納法+線段樹(遞歸)

gym101964G Matrix Queries seerc2018g題 數學歸納法+線段樹(遞歸)

targe scan gym weixin blog 數學歸納 大小 一行 spl

題目傳送門

題目大意:

  給出2^k大小的白色矩形,q次操作,每次將一行或者一列顏色反轉,問總體矩陣的價值,矩陣的價值定義是,如果整個矩陣顏色相同,價值為1,否則就把這個矩陣切成四份,價值為四個小矩陣的總價值加一。

思路:

  結論是,ans=不同色的子矩陣數*4+1,用數學歸納法證明。具體看 大佬的博客 。然後用線段樹維護這些,但是這個猜結論和線段樹都很牛逼,都是看大佬的博客學習的,我的代碼裏加了一些註釋,很神奇的題目。

技術分享圖片
#include<bits/stdc++.h>
#define CLR(a,b) memset(a,b,sizeof(a))
using namespace
std; typedef long long ll; const int inf=0x3f3f3f3f; const int maxn=(1<<20) +10; ll sum,tmp; ll seg[2][maxn<<2],ans[2][21];//ans表示2^k的行(列)有幾個同色的 int k,q; inline void mode(int id,int o,int l,int r,int x,int dep){ if(l==r){//染色 seg[id][o]^=1; return ; } int mid=(l+r)>>1
; if(x<=mid){ mode(id,(o<<1),l,mid,x,dep+1); }else{ mode(id,(o<<1)|1,mid+1,r,x,dep+1); } if(seg[id][o]!=-1)ans[id][dep]--; //當成不合法行,先減去 if(seg[id][o<<1]==seg[id][(o<<1)|1])seg[id][o]=seg[id][o<<1];//如果左右狀態一樣 則轉移(0,1,-1) else seg[id][o]=-1
; if(seg[id][o]!=-1)ans[id][dep]++;//仍然合法,加上 return ; } int main(){ cin>>k>>q; ll n=(1<<k); //sum表示總矩陣數 tmp表示合法數 for(int i=0;i<k;i++) { ans[0][i+1]=ans[1][i+1]=1ll*1<<i; sum+=1ll<<(i*2); } while(q--) { int op,x; scanf("%d%d",&op,&x); mode(op,1,1,n,x,1); tmp=0; for(int i=0;i<=k;i++) { tmp+=ans[0][i]*ans[1][i]; } printf("%lld\n",(sum-tmp)*4+1); } }
View Code

gym101964G Matrix Queries seerc2018g題 數學歸納法+線段樹(遞歸)