码迷,mamicode.com
首页 > 其他好文 > 详细

gym101964G Matrix Queries seerc2018g题 数学归纳法+线段树(递归)

时间:2018-12-03 00:45:51      阅读:230      评论:0      收藏:0      [点我收藏+]

标签:bit   颜色   turn   sed   play   分享图片   sdn   .com   article   

题目传送门

题目大意:

  给出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题 数学归纳法+线段树(递归)

标签:bit   颜色   turn   sed   play   分享图片   sdn   .com   article   

原文地址:https://www.cnblogs.com/mountaink/p/10056095.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!