给出N个[0, 65535]的整数,编程支持以下操作:
修改操作:C d,所有数增加d。如果超过65535,把结果模65536。0 <= d <= 65535
查询操作:Q i,统计有多少整数的第i位非0,换句话说,有多少个整数与2i的“按位与”操作值为正。0 <= i <= 15
输出所有查询操作的统计值。
输入格式:
第一行为两个正整数N和M,即整数的个数和操作的个数,第二行包含N个[0,65535]的整数。以下M行为各操作,格式如题所述。
输出格式:
输出M个数,即所有Q操作的统计值。
样例输入:
3 5 1 2 4 Q 1 Q 2 C 1 Q 1 Q 2
样例输出:
1 1 1 2
数据范围:
数据 1 2 3 4 5 6 7 8 9 10N 3 10 100 103 104 2*104 5*104 105 105 105
M 3 10 100 103 104 2*104 5*104 5*104 105 2*105
时间限制:
1000
空间限制:
512000
烧脑题,我们对于一个数,判断其第i位是零,当且仅当该数除以2^(i+1)次方大于等于2^i所以就转化为了求一段区间的和,加上一个数相当于该数组向右移动一段距离,这样子不如用一个头指针标志一下起始点,然后转前缀和这样就能在O(1)完成所有询问。
预处理复杂度O(n*16+65535*16) 这样就A了
下次遇到这种区间扔进去就不改的往头指针前缀和,转化区间和来解决。
#include<bits/stdc++.h>using namespace std;int a[17][1000001],len[17],l[17],siz[17],digit,n,m;string
type;int doit(int no,int st,int en){ if(st<=en) { if(st==0) return a[no][en]; else return a[no][en]-a[no][st-1]; } else return a[no][siz[no]-1]+a[no][en]-a[no][st-1];}int main(){ cin>>n>>m; for(int i=0;i<16;i++) { siz[i]=2<<i; l[i]=1<<i; len[i]=l[i]-1; } for(int i=1;i<=n;i++) { cin>>digit; for(int j=0;j<16;j++) { a[j][digit%siz[j]]++; } } for(int j=0;j<16;j++) for(int i=1;i<siz[j];i++) { a[j][i]+=a[j][i-1]; } while(m--) { cin>>type>>digit; if(type=="C") { for(int i=0;i<16;i++) { l[i]-=digit%siz[i]; if(l[i]<0)
l[i]+=siz[i]; } } else cout<<doit(digit,l[digit],(l[digit]+len[digit])%siz[digit])<<endl; }}
5044

被折叠的 条评论
为什么被折叠?



