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\n",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\n",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\n",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\n",need[i].u,need[i].v,need[i].w); 105 } 106 } 107 } 108 return 0; 109 }
E题,据说是树分治,但是现在不会这个算法。明天再补。