首页 > 代码库 > Codeforces Round #215 (Div. 1)

Codeforces Round #215 (Div. 1)

A Sereja and Algorithm

题意:给定有x,y,z组成的字符串,每次询问某一段s[l, r]能否变成变成zyxzyx的循环体。

分析:

分析每一段x,y,z数目是否满足构成循环体,当然长度<3的要特判。

代码:

 1 #include <bits/stdc++.h> 2 #define in freopen("solve_in.txt", "r", stdin); 3 #define pb push_back 4  5 using namespace std; 6 typedef long long LL; 7  8 const int maxn = (int)1e5 + 100; 9 char s[maxn];10 int cnt[maxn][3];11 int main() {12 13     int m;14     scanf("%s", s+1);15     scanf("%d", &m);16     int len = strlen(s+1);17     for(int i = 1; i <= len; i++) {18         for(int k = 0; k < 3; k++)19             cnt[i][k] = cnt[i-1][k];20         cnt[i][s[i]-x]++;21     }22     for(int i = 0; i < m; i++) {23         int l, r;24         scanf("%d%d", &l, &r);25         int a = cnt[r][0]-cnt[l-1][0];26         int b = cnt[r][1]-cnt[l-1][1];27         int c = cnt[r][2]-cnt[l-1][2];28         int tmp = r-l+1;29         if(tmp < 3)30             puts("YES");31         else {32 33             if(tmp%3 == 0) {34                 if(a == b && b == c)35                     puts("YES");36                 else puts("NO");37             } else if(tmp%3 == 1) {38                 if((a == b && c - b == 1) || (b == c && a-b == 1) || (a == c &&b -a == 1))39                     puts("YES");40                 else puts("NO");41             } else {42                 if((a == b && a-c == 1) || (b == c && b-a==1) || (a == c && a-b == 1))43                     puts("YES");44                 else puts("NO");45             }46         }47     }48     return 0;49 }
View Code

 

B Sereja ans Anagrams

题意:给定2个数组,a[1...n],以及b[1...m]问能否从a中等间隔的选取m个数,使得这m个数与b中各个整数数目对应相等。

分析:

容易知道由于是等间隔p的出现,所以可以将a[1..n]的数按间隔分成p组,每次添加一个数时,看相应的组m个数形成的序列是否和b中数的数目对应相等,每次添加,减少一个数,最多改变2个数的数目,看是不是所有的数的数目都满足与在b中的相等。感觉和单调队列类似。

代码:

 1 #include <bits/stdc++.h> 2 #define in freopen("solve_in.txt", "r", stdin); 3 #define pb push_back 4  5 using namespace std; 6 typedef long long LL; 7 typedef map<int, int> MPII; 8  9 const int maxn = 2*(int)1e5;10 int n, m, p;11 MPII mps, mx[maxn];12 vector<int> ans;13 int a[maxn], b[maxn];14 int sat[maxn];15 queue<int> q[maxn];16 17 int main() {18     19     scanf("%d%d%d", &n, &m, &p);20     for(int i = 0; i < n; i++) {21         scanf("%d", a+i);22     }23     int dif = 0;24     for(int i = 0; i < m; i++) {25         int t;26         scanf("%d", &t);27         if(mps[t] == 0)28             dif++;29         mps[t]++;30     }31     for(int i = 0; i < n; i++) {32         int di = i%p;33         if(q[di].size() >= m) {34             int u = q[di].front();35             q[di].pop();36             if(mx[di][u] == mps[u])37                 sat[di]--;38             else if(mx[di][u] == mps[u]+1)39                 sat[di]++;40             mx[di][u]--;41         }42         int u = a[i];43         q[di].push(a[i]);44         if(mx[di][u] == mps[u])45             sat[di]--;46         else if(mx[di][u] == mps[u]-1)47             sat[di]++;48         mx[di][u]++;49         if(sat[di] == dif)50             ans.pb(i-(m-1)*p);51     }52     cout<<ans.size()<<endl;53     for(int i = 0; i < ans.size(); i++) {54         printf("%d%c", ans[i]+1, i == ans.size()-1?\n: );55     }56     return 0;57 }
View Code

C Sereja and the Arrangement of Numbers

题意:n个位置,从m不同的数中选一些数去填充,构成一个数组,数组中出现的任何两个数一定要在数组中至少连续出现一次,每个数都有一个代价,要求选出的数总代价最大!

分析:首先肯定的是选出代价尽量大的数,那么就要确定n个位置最多放多少个不同的数,做的时候其实是想到了完全图的,但是没继续想下去。由于任何两个数都要相邻出现,所以肯定是满足完全图关系的,但是如果将相邻关系看做一条边的话,n个位置n-1条边,而且这n-1条边是能够从左走到右,也就是构成一个半欧拉图。

半欧拉图:最多有两个点度数为奇数。对于偶数个节点完全图,每个点度数为奇数,添加一条边能够使得两个点度数变为偶数,所以最少需要添加(点数/2-1)条边构成半欧拉图,因为最终还是允许两个点度数为奇数。奇数个结点完全图,度数为偶数,所以不需要添加边了。

这样根据,图中n-1条边二分最多能放置的结点数,得到数组中最多出现多少个不同的数,贪心选取最大就行了。

代码:

 1 #include <bits/stdc++.h> 2 #define in freopen("solve_in.txt", "r", stdin); 3 #define pb push_back 4  5 using namespace std; 6 typedef long long LL; 7 typedef map<int, int> MPII; 8 const int maxn = (int)1e5 + 100; 9 10 int w[maxn];11 int getAns(int lim, int r){12     int l = 1;13     while(l < r){14         int mid((l+r+1)>>1);15         int tmp;16         if(mid&1){17             tmp = ((LL)mid*(mid-1)>>1);18             if(tmp <= lim)19                 l = mid;20             else r = mid-1;21         }22         else {23             tmp = ((LL)mid*(mid-1)/2+mid/2-1);24             if(tmp <= lim)25                 l = mid;26             else r = mid-1;27         }28     }29     return l;30 }31 int main(){32 33     int n, m;34     scanf("%d%d", &n, &m);35     for(int i(0); i != m; i++){36         scanf("%*d%d", w+i);37     }38     sort(w, w+m, greater<int> ());39     n = getAns(n-1, m);40     LL ans = 0;41     for(int i = 0; i != n; i++)42         ans += w[i];43     cout<<ans<<endl;44     return 0;45 }
View Code

 

Codeforces Round #215 (Div. 1)