Educational Codeforces Round 54 ---1076ABCDE
1076A---Minimizing the String【字符串】
http://codeforces.com/contest/1076/problem/A
题意:
删掉字符串中的一个字符使得得到的字符串是字典序最小的一种。
思路:
从头到尾找到第一个字符他比他后面的一个字典序要大,那就是要删掉的。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<queue> 8 using namespace std; 9 #define ll long long 10 #define N 100010 11 #define pi 3.1415926535 12 13 int n; 14 const int maxn = 2e5 + 5; 15 char str[maxn], ans[maxn]; 16 17 int main() 18 { 19 while(scanf("%d", &n) != EOF){ 20 memset(ans, 0, sizeof(ans)); 21 memset(str, 0, sizeof(str)); 22 scanf("%s", str); 23 int len = 0; 24 bool flag = true; 25 for(int i = 0; i < n - 1; i++){ 26 if(str[i] > str[i + 1] && flag){ 27 flag = false; 28 continue; 29 } 30 ans[len++] = str[i]; 31 } 32 if(!flag){ 33 ans[len++] = str[n - 1]; 34 } 35 36 37 printf("%s\n", ans); 38 } 39 return 0; 40 }
1076B---Divisor Subtraction【数论】【思维】
http://codeforces.com/contest/1076/problem/B
题意:
给定一个数n,每次让他减掉他的最小质因子。问总共要减去多少次。
思路:
这题卡了好久....刚开始想着存一下质因子?但是存不下的啊。然后也想不到怎么优化时间。
对于n,如果他是偶数,那么他一定有质因子2。并且他减去2之后还是偶数,还是有质因子2.所以他的答案就是\(n/2\)
如果n是奇数,那么他减去了一个不是2的质因子之后就会变成偶数,就还是上面的步骤。那么现在就要找n的最小质因子。
找最小质因子其实根本不用去判断他是不是质数。这一点没想到有点傻了。
因为最小的因子肯定是质数否则肯定有一个比他还小的因子。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<queue> 8 #include<set> 9 using namespace std; 10 typedef long long LL; 11 #define N 100010 12 #define pi 3.1415926535 13 14 LL n; 15 16 bool isprime(LL x) 17 { 18 for(LL i = 2; i <= sqrt(x); i++){ 19 if(x % i == 0)return false; 20 } 21 return true; 22 } 23 24 LL getPri(LL x) 25 { 26 LL ans = -1; 27 for(LL j = 2; j * j <= x; j++){ 28 if(x % j == 0){ 29 if(ans == -1)return j; 30 while(x % j == 0)x /= j; 31 } 32 } 33 if(x > 1){ 34 if(ans == -1)return x; 35 } 36 return ans; 37 } 38 39 int main() 40 { 41 while(scanf("%lld", &n) != EOF){ 42 LL num = 0; 43 if(n % 2 == 0){ 44 num = n / 2; 45 } 46 else{ 47 for(LL j = 2; j * j <= n; j++){ 48 if(n % j == 0){ 49 n -= j; 50 num++; 51 break; 52 } 53 } 54 if(num == 0){ 55 n = 0; 56 num++; 57 } 58 num += n / 2; 59 } 60 61 printf("%lld\n", num); 62 } 63 return 0; 64 }
1076C---Meme Problem【公式】
http://codeforces.com/contest/1076/problem/C
题意:
给一个正整数d,要求你找出两个正数a和b,使得\(a+b=d,a*b=d\)
思路:
傻子我居然第一反应是二分。
直接代进去解方程就可以了。
\(x_{1,2} = \frac{d \pm \sqrt{d^{2}-4d}}{2}\),\(d^{2} - 4d < 0\)时不存在
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<queue> 8 #include<set> 9 using namespace std; 10 typedef long long LL; 11 #define N 100010 12 #define pi 3.1415926535 13 14 int t; 15 double d; 16 const double eps = 1e-6; 17 18 int main() 19 { 20 scanf("%d", &t); 21 while(t--){ 22 scanf("%lf", &d); 23 double delta = d * d - 4 * d; 24 if(delta < 0){ 25 printf("N\n"); 26 } 27 else{ 28 delta = sqrt(delta); 29 double a = (d - delta) / 2, b = (d + delta) / 2; 30 printf("Y %.9f %.9f\n", max(a,b), min(a,b)); 31 } 32 33 } 34 return 0; 35 }
1076D---Edge Deletion【最短路】【贪心】
http://codeforces.com/contest/1076/problem/D
题意:
给定一个n个节点m条边的图。现在要把边删到只有k条。删除边时要使尽可能多的节点i,节点1到节点i的最短路在删边前和删边后保持不变。
思路:
首先肯定要先跑dijstra找到单源最短路。
那么我们要删掉哪些边呢。这条边肯定尽可能少的出现在最短路的路径中。
由于dijkstra是用一种贪心的策略,他每次选的都是未拓展的且d最小的一个节点进行拓展。
如果\(d[j] > d[i]\),那么\(1~j\)的路中只要有\(i\)最短路就会经过\(i\)
所以得到最短路之后,可以按照d的大小排序,保留小的删除大的。
为了知道哪些边是留着的我们需要保存一下松弛时是由那条边拓展来的。
因为存的是双向边,所以最后输出的时候还需要处理一下。
注意d和队列都要开longlong
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<queue> 8 #include<set> 9 using namespace std; 10 typedef long long LL; 11 #define N 100010 12 #define pi 3.1415926535 13 14 const int maxn = 3e5 + 5; 15 int n, m, k; 16 int head[maxn]; 17 LL d[maxn]; 18 bool vis[maxn]; 19 struct edge{ 20 int v, nxt; 21 LL w; 22 }e[maxn * 2]; 23 int tot, pre[maxn]; 24 25 void addedge(int x, int y, LL z) 26 { 27 e[tot].v = y; 28 e[tot].w = z; 29 e[tot].nxt = head[x]; 30 head[x] = tot++; 31 e[tot].v = x; 32 e[tot].w = z; 33 e[tot].nxt = head[y]; 34 head[y] = tot++; 35 } 36 37 void dijkstra() 38 { 39 priority_queue<pair<LL, int> > que; 40 memset(d, 0x3f, sizeof(d)); 41 memset(vis, 0, sizeof(vis)); 42 43 d[1] = 0; 44 que.push(make_pair(0, 1)); 45 while(que.size()){ 46 int x = que.top().second;que.pop(); 47 if(vis[x])continue; 48 vis[x] = true; 49 for(int i = head[x]; i != -1; i = e[i].nxt){ 50 int y = e[i].v, z = e[i].w; 51 if(d[y] > d[x] + z){ 52 d[y] = d[x] + z; 53 que.push(make_pair(-d[y], y)); 54 pre[y] = i; 55 } 56 } 57 } 58 } 59 60 61 int main() 62 { 63 while(scanf("%d%d%d", &n, &m, &k) != EOF){ 64 tot = 0; 65 memset(head, -1, sizeof(head)); 66 for(int i = 0; i < m; i++){ 67 int x, y, z; 68 scanf("%d%d%d", &x, &y, &z); 69 addedge(x, y, 1LL * z); 70 } 71 dijkstra(); 72 73 vector<pair<LL, int>>vec; 74 for(int i = 2; i <= n; i++){ 75 //printf("%d\n", pre[i]); 76 vec.push_back(make_pair(d[i], pre[i])); 77 } 78 sort(vec.begin(), vec.end()); 79 vector<int>ans; 80 for(int i = 0; i < vec.size(); i++){ 81 if(i == k)break; 82 ans.push_back(vec[i].second); 83 } 84 cout<<ans.size()<<endl; 85 for(int i = 0; i < ans.size(); i++){ 86 if(ans[i] % 2 == 0){ 87 printf("%d ", ans[i] / 2 + 1); 88 } 89 else{ 90 printf("%d ", (ans[i] ^ 1) / 2 + 1); 91 } 92 } 93 printf("\n"); 94 } 95 return 0; 96 }
1076E---Vasya and a Tree【dfs】
http://codeforces.com/contest/1076/problem/E
题意:
给定给一个以1位根的树,现在给m次操作。每次操作给定v,d,x,表示更新以v为根的子树中距离v的距离是d之内的所有节点,将这些节点的值加上x。现在求更新完成之后各个节点的值。
思路:
我们将所有的更新操作统一进行。每次dfs下去进行更新。
沿着树的一条路径走,节点v的那些父节点的更新都会对v的值产生影响。我们就用一个数组add来记录这些影响。
并且用的前缀和的思想,\(add[l]\)表示从第\(l\)层往下更新的值,由于他要求更新的是一定范围内的节点。所以超过\(l+d\)层的就不更新了。
每一个节点只有可能被他的祖先或者自己更新,所以当dfs到他的时候,他的值就是他的结果了。
然后继续更新他的子孙。这里假设是二叉树,左子树更新完了之后,更新右子树的时候要左边的是更新不到右边的,所以要把add数组给恢复回来。相当于回溯。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<set> 10 using namespace std; 11 typedef long long LL; 12 #define N 100010 13 #define pi 3.1415926535 14 15 int n, m; 16 const int maxn = 3e5 + 5; 17 vector<int>edg[maxn]; 18 vector<pair<int, int> >op[maxn]; 19 LL ans[maxn], add[maxn]; 20 21 void dfs(int v, int fa, int h, LL sum) 22 { 23 for(int i = 0; i < op[v].size(); i++){ 24 int l = h, r = h + op[v][i].first; 25 add[l] += op[v][i].second; 26 if(r + 1 < maxn)add[r + 1] -= op[v][i].second; 27 } 28 sum += add[h]; 29 ans[v] = sum; 30 for(int i = 0; i < edg[v].size(); i++){ 31 if(edg[v][i] == fa)continue; 32 else{ 33 dfs(edg[v][i], v, h + 1, sum); 34 } 35 } 36 for(int i = 0; i < op[v].size(); i++){ 37 int l = h, r = h + op[v][i].first; 38 add[l] -= op[v][i].second; 39 if(r + 1 < maxn)add[r + 1] += op[v][i].second; 40 } 41 } 42 43 int main() 44 { 45 while(scanf("%d", &n) != EOF){ 46 for(int i = 0; i <= n; i++){ 47 edg[i].clear(); 48 op[i].clear(); 49 add[i] = 0; 50 ans[i] = 0; 51 } 52 for(int i = 1; i < n; i++){ 53 int x, y; 54 scanf("%d%d", &x, &y); 55 edg[x].push_back(y); 56 edg[y].push_back(x); 57 } 58 scanf("%d", &m); 59 for(int i = 0; i < m; i++){ 60 int v, d, x; 61 scanf("%d%d%d", &v, &d, &x); 62 op[v].push_back(make_pair(d, x)); 63 } 64 65 dfs(1, 0, 0, 0); 66 for(int i = 1; i <= n; i++){ 67 printf("%I64d", ans[i]); 68 if(i != n)printf(" "); 69 else printf("\n"); 70 } 71 } 72 73 return 0; 74 }