题目链接: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 }
A

 

  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 }
B

  

  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?'\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 }
C

 

  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 }
D

 

  E题,看了一会没怎么明白题意,暂时放过吧。