hdu 3670
题意:给出n个数,然后给出m个操作, 操作有两种类型:
1,将所有的数都加上一个给出的数
2,求出这n个数中在二进制下第t为是1的数目有多少个(0<=t<=15)
最后输出所有询问的和。
思路:这道题想了好久都没有想到。 具体思路是这样的。对于第一种操作, 我们记录当前已经加的和,对于第二问:
我们用16个树状数组, 每一个代表一个后缀。这样的话当询问的时候我们就可以利用 2^(t)<=(x+add)<2^(t+1)求出一个区间。 将区间中元素的数目加起来就行了。
AC代码:
View Code
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <string> 5 using namespace std; 6 typedef long long LL; 7 const int N = 65536, M = 101000; 8 9 int p[20][M], n; 10 11 int lowbit(int t) 12 { 13 return t&(t^(t-1)); 14 } 15 16 int sum(int k, int end) 17 { 18 int ans = 0; 19 end++; 20 while(end > 0) 21 { 22 ans += p[k][end]; 23 end -= lowbit(end); 24 } 25 return ans; 26 } 27 28 void add(int k, int pos, int num) 29 { 30 pos++; 31 while(pos < M) 32 { 33 p[k][pos] += num; 34 pos += lowbit(pos); 35 } 36 } 37 38 void init() 39 { 40 memset(p, 0, sizeof(p)); 41 int w, t; 42 for(int i=1; i<=n; i++) 43 { 44 scanf("%d", &w); 45 t = 0; 46 while(t<16) 47 { 48 add(t,w%(1<<(t+1)),1); 49 t++; 50 } 51 } 52 } 53 54 void solve(int k) 55 { 56 LL ans = 0; 57 int now = 0; 58 char ss[10]; 59 int w, tail; 60 while(scanf("%s", ss) && ss[0] != 'E') 61 { 62 scanf("%d", &w); 63 if(ss[0] == 'C') 64 { 65 now += w; 66 now %= N; 67 } 68 else 69 { 70 tail = now%(1<<w); 71 if(now&(1<<w)) 72 { 73 ans += sum(w, (1<<w)-tail-1);//0 74 ans += sum(w, (1<<(w+1))-1) - sum(w,(1<<w+1)-tail-1); 75 } 76 else 77 { 78 ans += sum(w, (1<<(w+1)) - tail-1) - sum(w, (1<<w)-1); 79 ans += sum(w, (1<<w)-1) - sum(w, (1<<w)-tail-1 ); 80 } 81 } 82 } 83 printf("Case %d: %I64d\n", k, ans); 84 } 85 86 int main() 87 { 88 int t=0; 89 while(scanf("%d", &n) && n!=-1) 90 { 91 init(); 92 t++; 93 solve(t); 94 } 95 return 0; 96 }


浙公网安备 33010602011771号