Codeforces Round #305 (Div. 2)
C. Mike and Frog
题意:有一只青蛙和一朵花,分别高度为h1、h2,每浇一次水,h1=(x1*h1+y1)mod m,h2=(x2*h2+y2)mod m。求最少浇多少次后h1=a1,h2=a2?
思路:先遍历m次找到第一次达到a1、a2的次数(若无,则为-1);再找到各自的循环节长度,然后枚举m次循环,判断能否符合题意。注意,可能在y2=0的时候,导致a2只出现一次,后面由于出现0而使得0对任意数取模都为0,则应当特别处理。
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 int main() 5 { 6 int m, a1, x1, y1, a2, x2, y2; 7 long long h1, h2; 8 scanf("%d", &m); 9 scanf("%I64d%d%d%d", &h1, &a1, &x1, &y1); 10 scanf("%I64d%d%d%d", &h2, &a2, &x2, &y2); 11 int len1=-1, len2=-1, st1=-1, st2=-1; 12 for (int i = 1; i <= 2 * m; i++) 13 { 14 h1 = (x1*h1 + y1) % m; 15 h2 = (x2*h2 + y2) % m; 16 if (h1 == a1) 17 { 18 if (st1 == -1) st1 = i; 19 else if (len1 == -1) len1 = i - st1; 20 } 21 if (h2 == a2) 22 { 23 if (st2 == -1) st2 = i; 24 else if (len2 == -1) len2 = i - st2; 25 } 26 if (len1 != -1 && len2 != -1) break; 27 } 28 if (st1 == -1 || st2 == -1||(len1==-1&&len2==-1&&st1!=st2)) printf("-1\n"); 29 else 30 { 31 bool flag = false; 32 for (int i = 0; i <= m; i++) 33 { 34 if (len1 > 0 && len2 > 0) 35 { 36 if ((1ll * st1 + 1ll * i * len1) >= st2 && (1ll * st1 + 1ll * i * len1 - st2) % len2 == 0) 37 { 38 printf("%I64d\n", 1ll * st1 + 1ll * i * len1); 39 flag = true; 40 break; 41 } 42 } 43 else if (len1 > 0) 44 { 45 if ((1ll * st1 + 1ll * i * len1) == st2) 46 { 47 printf("%I64d\n", 1ll * st1 + 1ll * i * len1); 48 flag = true; 49 break; 50 } 51 } 52 else break; 53 } 54 if (!flag) 55 { 56 for (int i = 0; i <= m; i++) 57 { 58 if (len1 > 0 && len2 > 0) 59 { 60 if ((1ll * st2 + 1ll * i * len2) >= st1 && (1ll * st2 + 1ll * i * len2 - st1) % len1 == 0) 61 { 62 printf("%I64d\n", 1ll * st2 + 1ll * i * len2); 63 flag = true; 64 break; 65 } 66 } 67 else if (len2 > 0) 68 { 69 if ((1ll * st2 + 1ll * i * len2) == st1) 70 { 71 printf("%I64d\n", 1ll * st2 + 1ll * i * len2); 72 flag = true; 73 break; 74 } 75 } 76 else break; 77 } 78 } 79 if (!flag) printf("-1\n"); 80 } 81 82 return 0; 83 } 84 /* 85 999983 86 408725 408721 87 1 1 88 378562 294895 89 984270 0 90 499981500166 91 */ 92 /* 93 16 94 1 0 95 2 0 96 1 2 97 2 0 98 -1 99 */
D. Mike and Feet
题意:有n只熊,每只熊有一个身高,他们站成一列。问区间长度为i时,所有区间最小值的最大值是多少?
思路:用单调栈分别求出每只熊其向左、向右最远的大于等于它身高的熊的位置。设为Li、Ri,则在区间[Li,Ri]内,熊i的身高是最低的,显然ans[Ri-Li+1]=max(ans[Ri-Li+1],h[i]),显然的,在该区间内,长度为min(i-Li+1,Ri-i+1)~Ri-Li+1的区间长度的最小值就为h[i],而对于该区间内区间长度小于min(i-Li+1,Ri-i+1)的最小值,自然可由那些位置的熊的Lj、Rj来确定。而我们此处设置最大范围为该最小值h[i],那么之后我们可以用大区间的值来更新小区间的值。另做证明:如果len1>len2,但是ans[len1]>ans[len2],说明大区间最小值的最大值比小区间的最小值的最大值还大,说明存在某一个长度为len1的大区间,其最小值为v1,那么显然在该大区间内部去一个长度为len2的小区间,则该小区间内最小值至少大于等于v1。故可用大区间的值来更新小区间的值。
1 #include<iostream> 2 #include<stack> 3 #include<algorithm> 4 #include<cstdio> 5 using namespace std; 6 const int maxn = 200010; 7 int v[maxn]; 8 int L_index[maxn]; 9 int R_index[maxn]; 10 int ans[maxn]; 11 int main() 12 { 13 int n; 14 scanf("%d", &n); 15 for (int i = 1; i <= n; i++) scanf("%d", v + i); 16 stack<int>stkL,stkR; 17 for (int i = 1; i <= n; i++) 18 { 19 while (!stkL.empty() && v[i] <= v[stkL.top()]) stkL.pop(); 20 if (stkL.empty()) L_index[i] = 1; 21 else L_index[i] = stkL.top() + 1; 22 stkL.push(i); 23 } 24 for (int i = n; i>=1; --i) 25 { 26 while (!stkR.empty() && v[i] <= v[stkR.top()]) stkR.pop(); 27 if (stkR.empty()) R_index[i] = n; 28 else R_index[i] = stkR.top() - 1; 29 stkR.push(i); 30 } 31 for (int i = 1; i <= n; i++) 32 { 33 int len = R_index[i] - L_index[i] + 1; 34 ans[len] = max(ans[len], v[i]); 35 } 36 for (int i = n-1; i >= 1; --i) 37 { 38 ans[i] = max(ans[i], ans[i + 1]); 39 } 40 for (int i = 1; i <= n; i++) 41 { 42 if (i > 1) printf(" "); 43 printf("%d", ans[i]); 44 } 45 printf("\n"); 46 47 return 0; 48 }
E. Mike and Foam
题意:有n杯啤酒,每杯啤酒的泡沫含量为ai。现在有一个空架子,q次询问,每次询问一杯啤酒的编号,如果其在架子上,则将其拿下,否则将其放上。并在每次询问后求架子上泡米含量互质的啤酒的对数。
思路:先求出含量ai其所有的质因子。然后求所有质因子的并集(容斥原理),得到与ai不互质的个数,然后架子上的啤酒个数减去ai就是与ai互质的对数。并且我们每次询问可以累积这个对数,这样每次无论是放上还是取下啤酒,都只需找到与进行操作的啤酒的互质的个数即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<vector> 5 using namespace std; 6 const int maxv = 500010; 7 const int maxn = 200010; 8 int v[maxn]; 9 bool isOnShelf[maxn]; 10 vector<int>p[maxv];//存放2~maxv各个数的质因子 11 int n, q; 12 int sets[maxv];//存放各个质因子及其乘积的个数 13 int preCount;//之前架子上的及啤酒个数 14 long long pre;//之前架子上互质的对数 15 void Init() 16 { 17 for (int i = 2; i < maxv; i++) 18 { 19 if (p[i].empty()) 20 { 21 for (int j = i; j < maxv; j += i) 22 { 23 p[j].push_back(i); 24 } 25 } 26 } 27 } 28 29 void removeBeer(int x) 30 { 31 int len = p[x].size(); 32 int tot = (1 << len) - 1; 33 int tans = 0; 34 //二进制枚举质因子个数,进行容斥,找到已有数的集合中与x不互质的个数(也就是含有至少一个相同质因子的个数,p1,p2,...,p_len的并集) 35 for (int i = 1; i <= tot; i++) 36 { 37 //得到当前状态下各质因子的乘积及其个数 38 int cur = 1,nums=0; 39 for (int j = 0; j < len; j++) 40 { 41 if ((1 << j)&i) 42 { 43 cur *= p[x][j], nums++; 44 } 45 } 46 //在cur的集合中减去一个数(即x自身的若干质因子的乘积),因为要把x从当前数的集合减去 47 sets[cur]--; 48 //奇加偶减 49 if (nums % 2) tans += sets[cur]; 50 else tans -= sets[cur]; 51 } 52 preCount--;//减去x自身 53 pre -= (preCount - tans); 54 } 55 void addBeer(int x) 56 { 57 int len = p[x].size(); 58 int tot = (1 << len) - 1; 59 int tans = 0; 60 //二进制枚举质因子个数,进行容斥,找到已有数的集合中与x不互质的个数(也就是含有至少一个相同质因子的个数,p1,p2,...,p_len的并集) 61 for (int i = 1; i <= tot; i++) 62 { 63 //得到当前状态下各质因子的乘积及其个数 64 int cur = 1, nums = 0; 65 for (int j = 0; j < len; j++) 66 { 67 if ((1 << j)&i) 68 { 69 cur *= p[x][j], nums++; 70 } 71 } 72 //奇加偶减 73 if (nums % 2) tans += sets[cur]; 74 else tans -= sets[cur]; 75 //在cur的集合中加去一个数(即x自身的若干质因子的乘积),因为要把x放入当前数的集合 76 sets[cur]++; 77 } 78 pre += (preCount - tans); 79 preCount++;//加上x自身 80 } 81 int main() 82 { 83 Init(); 84 scanf("%d%d", &n, &q); 85 for (int i = 1; i <= n; i++) scanf("%d", v + i); 86 while (q--) 87 { 88 int index; 89 scanf("%d", &index); 90 if (isOnShelf[index]) 91 { 92 removeBeer(v[index]); 93 printf("%I64d\n", pre); 94 isOnShelf[index] = false; 95 } 96 else 97 { 98 addBeer(v[index]); 99 printf("%I64d\n", pre); 100 isOnShelf[index] = true; 101 } 102 } 103 return 0; 104 }
出处:http://www.cnblogs.com/ivan-count/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。