题目链接:https://vjudge.net/contest/148543#overview。
A题:n个罪犯,每个人有一个犯罪值,现在要从里面选出连续的c个人,每个人的犯罪值都不能超过t,问选法的种类数。O(n)xjbg一下即可:
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #include <map> 5 #include <set> 6 #include <vector> 7 #include <queue> 8 #include <iostream> 9 using namespace std; 10 const int N = 200000 + 5; 11 typedef long long ll; 12 typedef pair<int,int> pii; 13 14 int a[N]; 15 16 int main() 17 { 18 int n,t,c; 19 cin >> n >> t >> c; 20 ll ans = 0; 21 int cnt = 0; 22 for(int i=1;i<=n;i++) 23 { 24 int temp;scanf("%d",&temp); 25 if(temp <= t) cnt++; 26 else 27 { 28 if(cnt >= c) ans += cnt - c + 1; 29 cnt = 0; 30 } 31 } 32 if(cnt >= c) ans += cnt - c + 1; 33 cout << ans << endl; 34 return 0; 35 }
B题:n个数字,从中选出不重叠的k段数字,每段的长度都为m,问最大的和。因为n是5000,所以很明显的开个二维数组n方dp一下即可:
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #include <map> 5 #include <set> 6 #include <vector> 7 #include <queue> 8 #include <iostream> 9 using namespace std; 10 const int N = 5000 + 5; 11 typedef long long ll; 12 typedef pair<int,int> pii; 13 14 ll pre[N]; 15 ll dp[N][N]; 16 17 int main() 18 { 19 int n,m,k; 20 cin >> n >> m >> k; 21 for(int i=1;i<=n;i++) 22 { 23 int x; 24 scanf("%d",&x); 25 pre[i] = pre[i-1] + x; 26 } 27 for(int i=m;i<=n;i++) 28 { 29 for(int j=1;j<=k;j++) 30 { 31 dp[i][j] = max(dp[i-1][j], dp[i-m][j-1] + pre[i] - pre[i-m]); 32 } 33 } 34 cout << dp[n][k] << endl; 35 return 0; 36 }
C题:给一个距离矩阵,问是否可能构成一棵树。做法是克鲁斯卡尔以后dfs一遍看看距离矩阵是否相等即可。仔细想想还是挺妙的。代码如下(写的有点挫):
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #include <map> 5 #include <set> 6 #include <vector> 7 #include <queue> 8 #include <iostream> 9 using namespace std; 10 const int N = 2000 + 5; 11 typedef long long ll; 12 typedef pair<int,int> pii; 13 14 int root[N],cnt,vis[N],last[N]; 15 int n,G[N][N],d[N][N]; 16 vector<pii> graph[N]; 17 void init() {for(int i=1;i<=n;i++) root[i] = i;} 18 int find(int x) {return x == root[x] ? x : root[x] = find(root[x]);} 19 void connect(int x,int y,int w) 20 { 21 int rx = find(x); 22 int ry = find(y); 23 if(rx != ry) 24 { 25 root[rx] = ry; 26 //d[x][y] = d[y][x] = w; 27 graph[x].push_back(pii(y,w)); 28 graph[y].push_back(pii(x,w)); 29 cnt--; 30 } 31 } 32 struct edge 33 { 34 int u,v,w; 35 bool operator < (const edge & temp) const 36 { 37 return w > temp.w; 38 } 39 }; 40 41 void dfs(int u,int fa) 42 { 43 for(int i=0;i<graph[u].size();i++) 44 { 45 pii p = graph[u][i]; 46 int v = p.first; 47 int w = p.second; 48 if(v == fa) continue; 49 last[v] = last[u] + w; 50 dfs(v,u); 51 } 52 } 53 54 int main() 55 { 56 scanf("%d",&n); 57 for(int i=1;i<=n;i++) 58 { 59 for(int j=1;j<=n;j++) 60 { 61 scanf("%d",&G[i][j]); 62 if(i == j && G[i][j]) return 0*puts("NO"); 63 } 64 } 65 for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(G[i][j] != G[j][i] || i!=j && G[i][j] == 0) return 0*puts("NO"); 66 priority_queue<edge> Q; 67 for(int i=1;i<=n;i++) 68 { 69 for(int j=1;j<i;j++) 70 { 71 Q.push((edge){i,j,G[i][j]}); 72 } 73 } 74 cnt = n; init(); 75 for(;cnt > 1;) 76 { 77 edge e = Q.top();Q.pop(); 78 connect(e.u, e.v, e.w); 79 } 80 //for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) printf("%d%c",d[i][j],j==n?' ':' '); 81 for(int i=1;i<=n;i++) 82 { 83 last[i] = 0; 84 dfs(i,-1); 85 for(int j=1;j<=n;j++) 86 { 87 if(j == i) continue; 88 if(last[j] != G[i][j]) return 0*puts("NO"); 89 } 90 } 91 puts("YES"); 92 return 0; 93 }
D题:给两个部分的字符串,分别重复n次和m次(最终长度相等),问有多少位置字符是不同的。只需要比较一个lcm里面的长度是肯定的,但暴力做肯定T。一个lcm中,考虑到只有pos%gcd这些位置需要比较。那么就可以线性的做出来了。最后扩大相应倍数即可。代码如下:
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #include <map> 5 #include <set> 6 #include <vector> 7 #include <queue> 8 #include <iostream> 9 using namespace std; 10 const int N = 1000000 + 5; 11 typedef long long ll; 12 typedef pair<int,int> pii; 13 14 ll n,m; 15 char a[N],b[N]; 16 int vis[N][30]; 17 18 int main() 19 { 20 cin >> n >> m; 21 scanf("%s%s",a+1,b+1); 22 int lena = strlen(a+1); 23 int lenb = strlen(b+1); 24 int g = __gcd(lena,lenb); 25 ll lcm = (ll)lena / g * lenb; 26 ll ans = 0; 27 for(int i=1;i<=lena;i++) vis[i%g][a[i]-'a']++; 28 for(int i=1;i<=lenb;i++) ans += vis[i%g][b[i]-'a']; 29 cout << 1LL*lena * n / lcm * (lcm - ans) << endl; 30 return 0; 31 }
E题,看了一会没怎么明白题意,暂时放过吧。