@01010101
2018-09-09T02:43:18.000000Z
字数 5297
阅读 1185
A 多色彩的巧克力
A.cpp /1s /256M
题目描述
奶牛 Bessie 有 N 块巧克力,从左往右排成一行,编号从 0 到 N-1。第 i 块巧克力的颜色是 color[i]。我们定义一个参数MaxLen,它表示:具有相同颜色的连续一段巧克力的最大长度。例如:有 10 块巧克力,颜色分别是: ADDDABBAAB,那么 MaxLen=3,因为有 3 块颜色是 D 的巧克力,而且这 3 块巧克力的位置是连续的。为了使得 MaxLen 最大,Bessie可以交换相邻两块巧克力的位置,但是 Bessie 总共交换的次数不能超过给定的值 swap。那么 MaxLen 的最大值是多少?
输入格式
多组测试数据。
第一行,一个整数 G,表示有 G 组测试数据。1 <= G <=5。
每组测试数据格式如下:
第一行,两个整数 N、swap 。1 <= N <= 50。 1 <= swap <= 2500。
第二行,N 个大写字母,第 i 个字母表示第 i 块巧克力的颜色。
输出格式
共 G 行,每行一个整数。
输入样例
4
7 1
ABCDCBC
7 2
ABCDCBC
9 3
ABBABABBA
9 4
ABBABABBA
输出样例
2
3
4
5
【样例解释】
第二组测试数据:交换后可以变成 ABDCCCB。
第三组测试数据:交换后可以变成 ABBBBAABA。
第四组测试数据:交换后可以变成 AABBBBBAA。
一开始想的是dp,dp[i][j]表示前i个交换j次的最大值。后来发现交换i后面的可能使答案更优,所以放弃了dp,选择了贪心。枚举中心i,考试的时候我还枚举了颜色j,但后来发现,如果中心的颜色和当前色块a[j]的颜色不同时在某些情况下可以得到最优解,但无法得到比中心颜色和当前色块颜色相同的更优解,所以颜色不用枚举,然后用k指针维护当前寻找到的点,l和r表示当前色块的左右端点。
其实考试时巨困,后来去洗了把脸就好了。
附上不优秀的考试代码。
int main(){T = read();while(T--){ans = 0;n = read();m = read();scanf("%s",a + 1);for(int i = 1; i <= n; ++i){//centrolmemset(col,0,sizeof(col));for(int j = 1; j <= n; ++j){//colif(col[a[j] - 'A']) continue;col[a[j] - 'A'] = 1;int k = 1,l = 0,r = 0,al = m,cnt = 0;if(a[i] == a[j]) {cnt = 1;l = r = 1;}for(; i - k >= 1 && i + k <= n; ++k){if((l == 1 && !r)|| (r == 1 && !l)) l = r = 1;if(a[j] == a[i - k] && al - (k - l) >= 0){al -= (k - l);l++;cnt++;}if(a[j] == a[i + k] && al - (k - r) >= 0){al -= (k - r);r++;cnt++;}}for(;i - k >= 1; ++k)if(a[j] == a[i - k] && al - (k - l) >= 0){al -= (k - l);l++;cnt++;}for(;i + k <= n; ++k)if(a[j] == a[i + k] && al - (k - r) >= 0){al -= (k - r);r++;cnt++;}ans = max(ans,cnt);}}printf("%d\n",ans);}return 0;}
C.Mushroom 的区间
C.cpp/1s/256M
【题目描述】
Mushroom 有一行数,初始时全部是 0。现在 Mushroom 有 m 个区间[L,R],他
希望用以下操作得到新的序列。
从 m 个给定区间中选择一个区间[s,t],把区间中的数对应元素全部翻转。(0 变
1,1 变 0)
请告诉 Mushroom 他能得到多少区间。(模 10^9+7)
【输入格式】
第一行包含两个整数 n,m。表示 n 个数和 m 个区间。
接下来 m 行是所表示的区间。
【输出格式】
一个整数,表示能得到的区间数。
【样例输入】
3 3
1 1
2 2
3 3
【样例输出】
8
【数据范围】
对于 30%的数据,n,m<=20
对于 60%的数据,n,m<=100
对于 100%的数据,n,m<=100000
【样例解释】
每个位置都可以单个修改,所以有 8 种可能。
开始找了几组,画了一下,后来画了Venn图,加上子集的枚举{0},{1},{2},{3},{1,2},{1,3},{2,3},{1,2,3}发现只有一段区间被完全覆盖时,即可以用之前的任意区间组成时,当前区间可以忽略。
所以考虑并查集维护,区间左开右闭。
开始时快速幂没开longlong差点见了祖宗。常数也要强转longlong
ll mul(ll a,ll b){ll ret = 1;while(b){if(b & 1) ret = ret * a % mod;a = a * a % mod;//!!b >>= 1;}return ret;}int Find(int u){return (fa[u] == u) ? u : fa[u] = Find(fa[u]);}int main(){int a,b;n = read();m = read();for(int i = 0; i <= n; ++i) fa[i] = i;while(m--){a = read();b = read();a -= 1;int x = Find(a);int y = Find(b);if(x != y){fa[x] = y;cnt++;}}printf("%lld\n",mul(2LL,(ll)cnt));return 0;}
A
CF 208B
题目大意:
给你n张牌,牌的花色和数字只要有一种一样就能合并。每次只能从最右边开始操作,可以覆盖n-1位置,可以覆盖 n-3位置。
问最后能否将全部牌合并成一堆。
暂时还没有想通。
B
CodeForces 709B
数轴上的越野赛,起点为a,数轴上有n个点,须至少到达n-1个点才算完成比赛。问完成比赛的最小路程。
(1 ≤ n ≤ 100 000, - 1 000 000 ≤ a ≤ 1 000 000)
水题,排序,要么不到1号点,要么不到n号点。然后在判断先跑左右哪边。
C
CodeForces 361B
题目大意:给出n,输出n的一个排列,使得其中下标i和a[i]的gcd不为1的个数有k个。
(1 ≤ n ≤ 105, 0 ≤ k ≤ n)
原来CF也有水题。
最后k个就令a[i] = i
前面的就奇偶互换。
如:1 2 3 4 5 -> 1 (3 2) (5 4)
1 2 3 4 5 6 -> (2,1) (4,3) (6,5)
D
CF 208C
题目大意:有n个城市,m条双向道路(每条边长度为1),让你添加一个警察局(有一个端点是警察局的边会变成安全边),使得安全边比上所有从1到n的最短路数的最大值。
n (2 ≤ n ≤ 100 )
其实思想不难。n的值极小,怎么应该都能过,结果是没开longlong见祖宗,CF居然报MLE。浪费了1h。
可以先找出从1到n的最短路条数,然后枚举哪个点i成为警察局最优。此处要记录跑最短路到i的入度,和从i跑最短路到n的出度。最后两者相乘*2/1到n的最短路条数.
题解对第22个数据的分析,n = 100 因为假设六个一组形成16个4叉路,剩下四个再形成三叉路,则总最短路条数为2^32*3,大于int范围。
queue <int> q;void bfs(){q.push(1);num[1] = 1;vis[1] = 1;while(!q.empty()){int u = q.front();q.pop();for(int i = head[u]; i != -1; i = e[i].nxt){if(!num[e[i].v]){dis[e[i].v] = dis[u] + 1;num[e[i].v] = num[u];q.push(e[i].v);a[e[i].v][u] = num[u];b[u][e[i].v] = 1;}else if(dis[e[i].v] == dis[u] + 1){num[e[i].v] += num[u];a[e[i].v][u] = num[u];b[u][e[i].v] = 1;}}}}int main(){int ab,aa;memset(head,-1,sizeof(head));scanf("%I64d%I64d",&n,&m);for(int i = 1; i <= m; ++i){scanf("%d%d",&aa,&ab);Adde(aa,ab);Adde(ab,aa);}bfs();double t = num[n],ans = 0;for(int i = 1; i <= n; ++i){if(a[n][i]) {vis[i] = 1;q.push(i);cntb[i] += 1;}}while(!q.empty()){int u = q.front();q.pop();for(int i = 1; i <= n; ++i){if(a[u][i]){cntb[i] += cntb[u];if(!vis[i]){vis[i] = 1;q.push(i);}}}}for(int i = 1; i <= n; ++i){if(b[1][i]) {q.push(i);cnta[i] += 1;}}while(!q.empty()){int u = q.front();q.pop();for(int i = 1; i <= n; ++i){if(b[u][i] && vis[i]){if(vis[i] == 1){vis[i] = 2;q.push(i);}cnta[i] += cnta[u];}}}ans = max(cnta[n] / t,cntb[1] / t);for(int i = 2; i < n; ++i) ans = max(ans,(double)2 * (cnta[i] * cntb[i]) / t);printf("%.10lf\n",ans);return 0;}
CodeForces 708A Letters Cyclic Shift
从仅由小写字母组成的字符串s中挑选出一个非空子串,将该子串中的每个字母均替换成前一个字母,如'b'换成'a','c'换成'b',以此类推,特别的,'a'要换成'z',问经过一次转换之后,字典序最小的字符串s为多少
水题,但是没有想到全是a的情况。
从头开始,遇到第一个不是a的字符开始变小,变到第一个a为止。
有一个陷阱是,如果字符串为全a,要把最后一个a变为z。
CF 709D
给出 a00 a01 a10 a11四个数,构造一个01序列。a00表示子序列为“00”数量。其余3个同理。若无合法的序列输出Impossible。
这题在学字符串时就做过,但没有AC,主要是因为此题太坑,特判太多,一定考虑最小值的特例以及最大值在计算过程或结果是否会溢出。
其实思路简单,就是先通过a00,a11计算出0,1的个数,要注意a00为0时,0的个数可能为1.
然后将0放在前面,1放在中间,0又放在最后,前两个构造a01,后两个构造a10,注意微调。
ll check(ll a){if(!a) return 0;ll t = sqrt(2 * a);for(int i = -5; i <= 5; ++i)if((t + i) > 0 && (t + i) * (t + i - 1) == 2 * a) return t + i;return -1;}int main(){scanf("%I64d%I64d%I64d%I64d",&a,&b,&c,&d);n = check(a);m = check(d);if(n == -1 || m == -1) {printf("Impossible\n");return 0;}if(!n && !m){if(!b && !c) {putchar('0');return 0;}if(b == 1 && !c) {printf("01");return 0;}if(!b && c == 1) {printf("10");return 0;}else {printf("Impossible\n");return 0;}}if(n == 0){if((b + c) && m && (b + c) != m) {printf("Impossible\n");return 0;}else if(b + c == 0 && m) {for(int i = 1; i <= m; ++i) putchar('1');return 0;}for(int i = 1; i <= c; ++i) putchar('1');putchar('0');for(int i = 1; i <= b; ++i) putchar('1');}else if(m == 0){if((b + c) && n && (b + c) != n) {printf("Impossible\n");return 0;}else if(b + c == 0 && n) {for(int i = 1; i <= n; ++i) putchar('0');return 0;}for(int i = 1; i <= b; ++i) putchar('0');putchar('1');for(int i = 1; i <= c; ++i) putchar('0');}else{if((b + c) != n * m) {printf("Impossible\n");return 0;}for(int i = 1; i <= b / m; ++i) putchar('0');for(int i = 1; i <= m - b % m; ++i) putchar('1');if(n > b / m) putchar('0');for(int i = 1; i <= b % m; ++i) putchar('1');for(int i = 1; i <= n - b / m - 1; ++i) putchar('0');}return 0;}