Topcoder Srm 649 DIV1
2015-02-11 16:49
309 查看
Srm 649 250pt Decipherability
题意:给出一个长度<= 50的字符串S,和一个数K,问从中删除K个字符后,得到的结果是否一定不产生歧义,即任意删除K个字符,不会有重复的结果出现。
思路,K = len(S)的时候,是唯一确定的。 当K不等于len(S)的时候,说明要保留len(S) - K个字符,枚举保留前i个字符和后j个字符,且 i + j == len(S) - K, 然后S[i + 1,j - 1]取一个字符,这一段肯定不能有重复字符出现,若有,一定有重复,否则,答案是唯一
Srm 649 550pt XorSequence
题意:给出一个长度<= 2^17 的序列A,序列中的每个数范围是[0,N - 1], N <= 20^30,你可以选择任意一个整数B,将A中的每个数都异或上B,得到序列C(C[i] = A[i] ^ B)。问在恰当选择B的情况下,最多有多少个关系对(C[i],C[j]),其中i < j 且C[i] < C[j]
思路:异或涉及位运算,将每个数 A[i] 转化成二进制表示形式,对于前缀相同的数,B的相同长度前缀异或对结果无影响。可以将每个数都插入到一个trie树中。trie中的节点记录几个信息,一个是下一个分支为1或0的数的个数,另一个是当B这个数取1或0的时候,后缀中C[i] < C[j]的对数,这样的意义是从根节点到当前节点,前缀是相同的,前面说过前缀相同的话,B的相同长度前缀对结果无影响,对于第一个不相同的最高位,看看B对应的这一位取0或者取1的满足条件(C[I] < C[J])的数对,因为数是从前往后插入的,所以每来一个点统计一次的话,i
< j这个条件是已经保证了的。 然后对于每个深度,将trie中这个深度的所有为0或所有为1的加起来,和最大的就是相同前缀下,下一位取0或取1的最大值,分位(深度)求和即可。
Srm 649 850pt CartInSupermarket
题意:给出一堆数,数目不大于50个,每个数的范围是[0,10^9],再给出一个数b。对于每分钟,对于每个大于0的数a,可以同时进行以下两个操作之一:(1)将这个数减去1;(2)将一个分成两个整数x,y,其中a = x + y。限制只有一个,就是(2)操作总数不能超过b. 问在最优的操作情况下,使所有数变为0的最少需要多少分钟。
思路:对于一个数来说,肯定是先进行若干次(2)操作,然后再均分进行(1)操作的。(2)操作总数越多,显然是越有可能减少时间的(总操作数b未必要用完)。可以选择二分时间,b与时间显然是具有单调关系,因此我们可以算出每个数在特定需要的时间下,最少使用(2)的操作次数,其总和如果<=b,说明这个时间点是可以的,否则需要更多的时间。
二分最少需要的时间time后,现在的问题变成了对于一个数a,使得它在不超过time的时间内变为0,至少要分成多少块。首先要明确一个概念,因为是并行操作的,所以对于一个数来说,肯定是尽量均分的,这个均分的话,是在一个满二叉树的叶子上进行。由于满二叉树每一次拓展出比前面多一倍的叶子节点,所以可以枚举枚举最终分成多少块(即叶子节点个数),然后算出满二叉树的深度(即叶子节点数>=块数需要的时间),然后对于剩余的节点均分,剩余最多的是((总数 + 块数 - 1) / 块数,+块数-1即不整除的时候,有至少一个节点数量是总数/块数+1),这个最终分成多少块,在块数不大于节点数的时候也是具有单调性的,所以这一步可以选择二分分成多少块。
计算的时候还有一个需要注意的,因为满二叉树的叶子节点未必要用完,可能将一些点移动到上一层,这样叶子总数也是够的,然后上一层分配的每个叶子节点,在其他点进行最后一次分裂的时候,它们可以进行一次(1)操作,所以要将总数 - 进行(1)操作的数目,然后再进行均分。
题意:给出一个长度<= 50的字符串S,和一个数K,问从中删除K个字符后,得到的结果是否一定不产生歧义,即任意删除K个字符,不会有重复的结果出现。
思路,K = len(S)的时候,是唯一确定的。 当K不等于len(S)的时候,说明要保留len(S) - K个字符,枚举保留前i个字符和后j个字符,且 i + j == len(S) - K, 然后S[i + 1,j - 1]取一个字符,这一段肯定不能有重复字符出现,若有,一定有重复,否则,答案是唯一
Srm 649 550pt XorSequence
题意:给出一个长度<= 2^17 的序列A,序列中的每个数范围是[0,N - 1], N <= 20^30,你可以选择任意一个整数B,将A中的每个数都异或上B,得到序列C(C[i] = A[i] ^ B)。问在恰当选择B的情况下,最多有多少个关系对(C[i],C[j]),其中i < j 且C[i] < C[j]
思路:异或涉及位运算,将每个数 A[i] 转化成二进制表示形式,对于前缀相同的数,B的相同长度前缀异或对结果无影响。可以将每个数都插入到一个trie树中。trie中的节点记录几个信息,一个是下一个分支为1或0的数的个数,另一个是当B这个数取1或0的时候,后缀中C[i] < C[j]的对数,这样的意义是从根节点到当前节点,前缀是相同的,前面说过前缀相同的话,B的相同长度前缀对结果无影响,对于第一个不相同的最高位,看看B对应的这一位取0或者取1的满足条件(C[I] < C[J])的数对,因为数是从前往后插入的,所以每来一个点统计一次的话,i
< j这个条件是已经保证了的。 然后对于每个深度,将trie中这个深度的所有为0或所有为1的加起来,和最大的就是相同前缀下,下一位取0或取1的最大值,分位(深度)求和即可。
#include <bits/stdc++.h> using namespace std; struct trie { trie *next[2]; long long val[2]; int cnt[2]; trie() { next[0] = next[1] = NULL; val[0] = val[1] = cnt[0] = cnt[1] = 0; } }e[(1 << 17) * 30 + 100],*root; int cnt = 0; void insert(int x) { trie *p = root; for(int i = 29; i >= 0; i --) { int idx = (x & (1 << i)) ? 1 : 0; p->cnt[idx] ++; p->val[idx] += p->cnt[idx ^ 1]; if(!p->next[idx]) p->next[idx] = &e[cnt ++]; p = p->next[idx]; } }; long long c[35][2]; void dfs(trie *root,int dep) { c[dep][0] += root->val[0]; c[dep][1] += root->val[1]; if(root->next[0]) dfs(root->next[0],dep - 1); if(root->next[1]) dfs(root->next[1],dep - 1); } struct XorSequence { long long getmax(int N, int sz, int A0, int A1, int P, int Q, int R) { root = &e[cnt ++]; insert(A0); insert(A1); for(int i = 2; i < sz; i ++) { int A2 = (1LL * A0 * P + 1LL * A1 * Q + R) % N; insert(A2); A0 = A1; A1 = A2; } dfs(root,30); long long ans = 0; for(int i = 1; i <= 30; i ++) { ans += max(c[i][0],c[i][1]); } return ans; } };
Srm 649 850pt CartInSupermarket
题意:给出一堆数,数目不大于50个,每个数的范围是[0,10^9],再给出一个数b。对于每分钟,对于每个大于0的数a,可以同时进行以下两个操作之一:(1)将这个数减去1;(2)将一个分成两个整数x,y,其中a = x + y。限制只有一个,就是(2)操作总数不能超过b. 问在最优的操作情况下,使所有数变为0的最少需要多少分钟。
思路:对于一个数来说,肯定是先进行若干次(2)操作,然后再均分进行(1)操作的。(2)操作总数越多,显然是越有可能减少时间的(总操作数b未必要用完)。可以选择二分时间,b与时间显然是具有单调关系,因此我们可以算出每个数在特定需要的时间下,最少使用(2)的操作次数,其总和如果<=b,说明这个时间点是可以的,否则需要更多的时间。
二分最少需要的时间time后,现在的问题变成了对于一个数a,使得它在不超过time的时间内变为0,至少要分成多少块。首先要明确一个概念,因为是并行操作的,所以对于一个数来说,肯定是尽量均分的,这个均分的话,是在一个满二叉树的叶子上进行。由于满二叉树每一次拓展出比前面多一倍的叶子节点,所以可以枚举枚举最终分成多少块(即叶子节点个数),然后算出满二叉树的深度(即叶子节点数>=块数需要的时间),然后对于剩余的节点均分,剩余最多的是((总数 + 块数 - 1) / 块数,+块数-1即不整除的时候,有至少一个节点数量是总数/块数+1),这个最终分成多少块,在块数不大于节点数的时候也是具有单调性的,所以这一步可以选择二分分成多少块。
计算的时候还有一个需要注意的,因为满二叉树的叶子节点未必要用完,可能将一些点移动到上一层,这样叶子总数也是够的,然后上一层分配的每个叶子节点,在其他点进行最后一次分裂的时候,它们可以进行一次(1)操作,所以要将总数 - 进行(1)操作的数目,然后再进行均分。
#include <bits/stdc++.h> using namespace std; typedef pair<int,int> pii; typedef vector<int> vi; typedef vector<int>::iterator vit; struct CartInSupermarket { map<long long,int> ma; long long calc_min_time(int a,long long b) { if(b == 1) return a; int i = 0; while((1LL << i) < b) i ++; a -= (1LL << i) - b; return i + (a + b - 1) / b; } long long calc_min_split(int a,int time) { if(!time && a) return 1LL << 50; long long lt = 1,rt = a + 1,mid,ans = 1LL << 50; while(lt <= rt) { mid = lt + rt >> 1; if(calc_min_time(a,mid) <= time) ans = mid,rt = mid - 1; else lt = mid + 1; } return ans - 1; } int calcmin(vector <int> a, int b) { long long lt = 0,rt = *max_element(a.begin(),a.end()); long long ans = 0; while(lt <= rt) { long long mid = lt + rt >> 1; long long sum = 0; for(int i = 0; i < a.size(); i ++) sum += calc_min_split(a[i],mid); if(sum <= b) ans = mid,rt = mid - 1; else lt = mid + 1; } return ans; } };
相关文章推荐
- TopCoder SRM 649 Div2 Problem 1000 - XorSequenceEasy (思维)
- TopCoder SRM 144 DIV2 550points
- topcoder srm 704 div1
- TopCoder SRM 512 DIV1 MysteriousRestaurant
- TopCoder——SRM 516 DIV 2
- TopCoder 250 points 15-SRM 151 DIV 1 121.73/250 48.69%
- TopCoder SRM 647 Div2 Problem 500 - TravellingSalesmanEasy (思维)
- Topcoder SRM 583 DIV2 解题报告
- topcoder SRM 625 DIV2 IncrementingSequence
- topcoder srm 693 div1 -3
- Topcoder SRM 655 DIV1 250 CountryGroupHard
- topcoder srm 510 div1
- TopCoder SRM 590 Div2 第3题
- [TopCoder] SRM 587 DIV 2, 250p, 500p, 1000p, Solution
- TopCoder SRM 597 Div1 第1题
- topcoder SRM 548 DIV2 250
- Topcoder SRM 616 Div2 1000 TwoLLogo
- topcoder srm 585 div1
- topcoder SRM 637 div2+div1 250
- topcoder srm 320 div1