A题,水题,不过我写的时候少考虑了一个细节导致WA了一发。
B题,水题,判断一行内元音字母的个数是不是等于p[i]即可。
C题,好题,反过来思考,用并查集离线处理。每次如果能合并就合并并更新答案即可。代码如下:
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #include <iostream> 5 #include <queue> 6 using namespace std; 7 typedef long long ll; 8 const int N = 100000 + 5; 9 10 int n; 11 ll a[N]; 12 int root[N]; 13 bool have[N]; 14 ll ans[N]; 15 int des[N]; 16 int find(int x) {return x == root[x] ? x : root[x] = find(root[x]);} 17 void init() 18 { 19 for(int i=1;i<=n;i++) root[i] = i; 20 memset(have,false,sizeof have); 21 } 22 23 int main() 24 { 25 cin >> n; 26 for(int i=1;i<=n;i++) scanf("%I64d",a+i); 27 for(int i=1;i<=n;i++) scanf("%d",des+i); 28 init(); 29 ll now = 0; 30 for(int i=n;i>=1;i--) 31 { 32 int p = des[i]; 33 have[p] = true; 34 now = max(now, a[p]); 35 if(p - 1 >= 1 && have[p-1]) 36 { 37 int rx = find(p-1); 38 int ry = find(p); 39 root[ry] = rx; 40 a[rx] += a[ry]; 41 now = max(now, a[rx]); 42 } 43 if(p + 1 <= n && have[p+1]) 44 { 45 int rx = find(p); 46 int ry = find(p+1); 47 root[ry] = rx; 48 a[rx] += a[ry]; 49 now = max(now, a[rx]); 50 } 51 ans[i-1] = now; 52 } 53 for(int i=1;i<=n;i++) printf("%I64d ",ans[i]); 54 return 0; 55 }
D题,之前做过一次,这次还是没有能够完全正确的解答出来(而且之前写的博客有点问题)。。正确的贪心思路是,每次取出集合中最大的元素,不断地除以2直到这个数不在集合中出现为止。再把当前这个数放到集合中,如果不能够创造出新的数,那么就结束算法。只除1次和一直除到不能再除为止这两种思路都是错误的。代码如下:
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #include <iostream> 5 #include <queue> 6 #include <map> 7 #include <set> 8 using namespace std; 9 typedef long long ll; 10 const int N = 100000 + 5; 11 12 int n; 13 set<int> S; 14 15 int main() 16 { 17 cin >> n; 18 for(int i=1;i<=n;i++) 19 { 20 int t; 21 scanf("%d",&t); 22 S.insert(t); 23 } 24 while(1) 25 { 26 set<int>::iterator it = S.end(); 27 it--; 28 int now = *it; 29 //S.erase(it); 30 while(S.find(now) != S.end() && now) now >>= 1; 31 if(now == 0) break; 32 S.erase(it); 33 S.insert(now); 34 } 35 for(set<int>::iterator it=S.begin();it!=S.end();it++) printf("%d ",*it); 36 puts(""); 37 return 0; 38 }