CodeForces 400E Inna and Binary Logic

来源:互联网 发布:nba数据库统计2017 编辑:程序博客网 时间:2024/05/05 14:55

题意:

n个数字m个操作  n个数组堆成一个金字塔  a[i][j](表示第i行第j个数)=a[i+1][j] & a[i+1][j+1]  (反正就是一个三角形…  不懂自己读读题…)  每次操作修改最底层的一个数字  问  整个金字塔的数字的和是多少


思路:

数据很大就算建树也是n-1的高度  所以我放弃这个方向

由于题目中都是位运算  所以自然思路往位上面偏  想到每个元素最大2^17因此可以把17位分开讨论  也就是每一位建一个金字塔

然后发现金字塔里面的一团相邻的1的个数有个特点  就是最底层连续x个1  那么这团1的个数就为x*(x+1)/2

然后就想到一开始先算一个最初形态的ans  然后每次更改元素只需要维护一段连续的1  把ans加加减减就好

用l[i][j]表示在i这个金字塔内最底层第j个数字可以向左延伸l[i][j]个1  同理r[i][j]

那么对该金字塔的一次更改可以分两种情况:

1.将0变成1

那么ans可以先减去更改位置左边和右边的两团1  再加上更改后两边连成一团的1  同时更新l和r数组

2.将1变成0 

那么ans可以先减去更改位置所在的那一团1  在加上该位置左边和右边的两团1  同时更新l和r


PS:

我在更新l和r时是暴力的  从纯理论上讲可能会有把我时间卡掉的数据  不过我没想出来  最后AC的结果也是程序只需要202ms  在已经有的解决方案中算快的


代码:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define M 100010#define K 19int l[K][M],r[K][M],num[M];int n,m;__int64 ans;int main(){    int i,j,k,las,pos,val,from,to;    scanf("%d%d",&n,&m);    for(i=1;i<=n;i++) scanf("%d",&num[i]);    for(i=0;i<K;i++)    {        las=0;        for(j=1;j<=n+1;j++)        {            if( (1<<i)&num[j] )            {                l[i][j]=las;            }            else            {                l[i][j]=r[i][j]=j;                for(k=las+1;k<j;k++) r[i][k]=j;                ans+=(1LL<<i)*(j-las-1)*(j-las)/2;                las=j;            }        }    }    //printf("%I64d\n",ans);    while(m--)    {        scanf("%d%d",&pos,&val);        for(i=0;i<K;i++)        {            from=((1<<i)&num[pos]);            to=((1<<i)&val);            if( from == to ) continue;            if(from) //1->0            {                ans-=(1LL<<i)*(r[i][pos]-l[i][pos]-1)*(r[i][pos]-l[i][pos])/2;                l[i][pos]=r[i][pos]=pos;                for(j=pos-1;j>=0&&(num[j]&(1<<i));j--) r[i][j]=pos;                ans+=(1LL<<i)*(pos-j-1)*(pos-j)/2;                for(j=pos+1;j<=n+1&&(num[j]&(1<<i));j++) l[i][j]=pos;                ans+=(1LL<<i)*(j-pos-1)*(j-pos)/2;            }            else //0->1            {                ans-=(1LL<<i)*(r[i][pos-1]-l[i][pos-1]-1)*(r[i][pos-1]-l[i][pos-1])/2;                ans-=(1LL<<i)*(r[i][pos+1]-l[i][pos+1]-1)*(r[i][pos+1]-l[i][pos+1])/2;                ans+=(1LL<<i)*(r[i][pos+1]-l[i][pos-1]-1)*(r[i][pos+1]-l[i][pos-1])/2;                l[i][pos]=l[i][pos-1];                r[i][pos]=r[i][pos+1];                for(j=pos-1;j>=0&&(num[j]&(1<<i));j--) r[i][j]=r[i][pos];                for(j=pos+1;j<=n+1&&(num[j]&(1<<i));j++) l[i][j]=l[i][pos];            }        }        num[pos]=val;        printf("%I64d\n",ans);    }    return 0;}



0 0
原创粉丝点击