Codeforces Round #372 (Div. 2)

  A题,水题,但是因为我自己的写法没特判n是1导致WA了一次。

  B题,直接用数组记录一下各个字母出现的次数即可,问号另外统计,然后每26个看看是否可行,如果可行那么其他的问号随便放就好。用map记录WA了一次,因为map里只要一个节点被用来记录过,然后被减到0,使用size()访问也会把这个节点计算在内的,需谨记。

  C题,假设等级i时起始的数是a[i],由题意它是i的倍数。假设需要增加的数为ans[i],那么,a[i]+ans[i]*i=a[i+1]*a[i+1]。左边都是i的倍数,因此右边也一定是i的倍数,所以,a[i+1]同时是i+1和i的倍数。那么我们直接构造a[i+1]=i*(i+1),即a[i]=i*(i-1)即可。当然i=1的时候需要特判,是2(题目规定)。然后就很好求ans[i]了。

  D题,好题。题意是给出一个图,和若干的边,其中权值为0的边是待定的边,问是否能够修改这些所有待定的边的权值(都变为一个正整数),使得s到t的最短路恰好为L。注意这题点的个数为n,因此可以考虑暴力的方法的。首先,不考虑这些待定的边,做s到t的最短路,得D,如果D小于L,显然答案是不可能的,如果等于L,那么待定的边都变为inf即可。否则,开始暴力。拿出所有的待定的边,让其权值变为1,再做s到t的最短路,如果新的D不比L大,那么这条边的权值再加上L-D即可(其他的待定边都变为inf)。如果所有的待定边都考虑了,仍不能完成实现上面的结果,那么答案就是不可能的。代码如下:

  1 #include <stdio.h>
  2 #include <algorithm>
  3 #include <string.h>
  4 #include <iostream>
  5 #include <set>
  6 #include <map>
  7 #include <vector>
  8 #include <queue>
  9 using namespace std;
 10 const int N = 1000 + 5;
 11 typedef long long ll;
 12 const ll inf = 1e18-100;
 13 typedef pair<ll,int> pii;
 14 
 15 int n,m,L,s,t;
 16 struct edge
 17 {
 18     int u,v;
 19     ll w;
 20 };
 21 vector<edge> G[N];
 22 vector<edge> need,for_print;
 23 void addEdge(int u,int v,ll w)
 24 {
 25     if(w == 0) need.push_back((edge){u,v,w});
 26     else
 27     {
 28         G[u].push_back((edge){u,v,w});
 29         G[v].push_back((edge){v,u,w});
 30         for_print.push_back((edge){u,v,w});
 31     }
 32 }
 33 ll dis[N];
 34 ll dij()
 35 {
 36     for(int i=0;i<n;i++) dis[i] = i == s ? 0 : inf;
 37     priority_queue<pii,vector<pii>,greater<pii> > Q;
 38     Q.push(pii(0,s));
 39     while(!Q.empty())
 40     {
 41         pii x = Q.top();Q.pop();
 42         ll d = x.first;
 43         int u = x.second;
 44         if(dis[u] < d) continue;
 45         for(int i=0;i<G[u].size();i++)
 46         {
 47             edge &e = G[u][i];
 48             int v = e.v;
 49             ll w = e.w;
 50             if(dis[v] > dis[u] + w)
 51             {
 52                 dis[v] = dis[u] + w;
 53                 Q.push(pii(dis[v], v));
 54             }
 55         }
 56     }
 57     return dis[t];
 58 }
 59 
 60 int main()
 61 {
 62     cin >> n >> m >> L >> s >> t;
 63     for(int i=1;i<=m;i++)
 64     {
 65         int u,v,w;
 66         scanf("%d%d%d",&u,&v,&w);
 67         addEdge(u,v,w);
 68     }
 69     ll D = dij();
 70     if(D < L) puts("NO");
 71     else if(D == L)
 72     {
 73         puts("YES");
 74         for(int i=0;i<for_print.size();i++) printf("%d %d %I64d
",for_print[i].u,for_print[i].v,for_print[i].w);
 75         for(int i=0;i<need.size();i++) printf("%d %d %I64d
",need[i].u,need[i].v,inf);
 76     }
 77     else
 78     {
 79         int flag = 0;
 80         for(int i=0;i<need.size()&&flag==0;i++)
 81         {
 82             edge &e = need[i];
 83             e.w = 1;
 84             int u = e.u, v = e.v;
 85             ll w = e.w;
 86             G[u].push_back((edge){u,v,w});
 87             G[v].push_back((edge){v,u,w});
 88             ll D = dij();
 89             if(D <= L)
 90             {
 91                 flag = 1;
 92                 e.w += L - D;
 93                 break;
 94             }
 95         }
 96         if(flag == 0) puts("NO");
 97         else
 98         {
 99             puts("YES");
100             for(int i=0;i<for_print.size();i++) printf("%d %d %I64d
",for_print[i].u,for_print[i].v,for_print[i].w);
101             for(int i=0;i<need.size();i++)
102             {
103                 if(need[i].w == 0) need[i].w = inf;
104                 printf("%d %d %I64d
",need[i].u,need[i].v,need[i].w);
105             }
106         }
107     }
108     return 0;
109 }
D

  E题,据说是树分治,但是现在不会这个算法。明天再补。

原文地址:https://www.cnblogs.com/zzyDS/p/6354510.html