关于一些水题,思维题,套路dp菜得不行,于是点了个dp-tag,开了这个坑
目前困于水平只限制了1k4到1k8分数段的题,按过题人数降序,1k6+就很虐我了估计放开上限到2k+就受不了了QAQ
由于cf的tag机制,混了一些奇怪的东西不太像dp的题进来,能练手的也尽量写了
总之,为了队友,为了湘潭邀请赛和女生赛,赶紧提高到能独立完成gym3x的程度吧(还是太菜了QAQ
455A - 删a[k]会删除所有a[k]-1和a[k]+1,获得a[k]
dp[i]为数字1-i能获得的最大价值
1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 #include <algorithm>
5 #define LL long long
6 #define INF 0x3f3f3f3f
7 #define debug(x) cout << #x << " = " << x << endl;
8 using namespace std;
9
10 const int mx = 1e5;
11 LL dp[mx+7];
12 int vis[mx+10];
13
14 int main(){
15 int n, a, m = 0;
16 scanf("%d", &n);
17 for (int i = 1; i <= n; i++) {
18 scanf("%d", &a);
19 m = max(m, a);
20 vis[a]++;
21 }
22 dp[1] = vis[1];
23 for (int i = 2; i <= m; i++){
24 dp[i] = max(dp[i-1], dp[i-2]+1ll*vis[i]*i);
25 }
26 printf("%lld\n", dp[m]);
27 return 0;
28 }
466C - 数组划分成相等三段的方案数
1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 #include <algorithm>
5 #include <vector>
6 #define LL long long
7 #define INF 0x3f3f3f3f
8 #define debug(x) cout << #x << " = " << x << endl;
9 using namespace std;
10
11 const int mx = 5e5+7;
12 LL sum[mx];
13
14 int main(){
15 int n, c;
16 scanf("%d", &n);
17 for (int i = 1; i <= n; i++){
18 scanf("%d", &c);
19 sum[i] = sum[i-1]+c;
20 }
21 vector<int> a, b;
22 for (int i = 1; i < n; i++){
23 if (sum[i]*3 == sum[n]) a.push_back(i);
24 if (sum[i]*3 == sum[n]*2) b.push_back(i);
25 }
26 LL ans = 0;
27 for (int i = 0; i < a.size(); i++){
28 int k = upper_bound(b.begin(), b.end(), a[i])-b.begin();
29 ans += b.size()-k;
30 }
31 printf("%lld\n", ans);
32 return 0;
33 }
698A - 每天能做事或者休息,两天不做一样的事,最小休息天数
dp[i][0/1/2]当天做的事/休息
1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 #include <algorithm>
5 #define LL long long
6 #define INF 0x3f3f3f3f
7 #define debug(x) cout << #x << " = " << x << endl;
8 using namespace std;
9
10 const int mx = 110;
11 int dp[mx][3];
12
13 int main(){
14 int n, a;
15 scanf("%d", &n);
16 memset(dp, INF, sizeof dp);
17 //dp[i][0/1/2]
18 dp[0][0] = 0;
19 for (int i = 1; i <= n; i++) {
20 scanf("%d", &a);
21 dp[i][0] = min(dp[i-1][0], min(dp[i-1][1], dp[i-1][2]))+1;
22 if (!a) continue;
23 if (a != 2) dp[i][2] = min(dp[i-1][0], dp[i-1][1]);
24 if (a != 1) dp[i][1] = min(dp[i-1][0], dp[i-1][2]);
25 }
26 printf("%d\n", min(dp[n][0], min(dp[n][1], dp[n][2])));
27 return 0;
28 }
545C - n棵树砍了往左或者往右倒,不能倒在一起,最大砍伐数
dp[i][0/1]当前往左或者往右倒
1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 #include <algorithm>
5 #include <vector>
6 #define LL long long
7 #define INF 0x3f3f3f3f
8 #define debug(x) cout << #x << " = " << x << endl;
9 using namespace std;
10
11 const int mx = 1e5+7;
12 LL x[mx], h[mx];
13 int dp[mx][2];
14
15 int main(){
16 int n;
17 scanf("%d", &n);
18 for (int i = 1; i <= n; i++) scanf("%lld%lld", &x[i], &h[i]);
19 dp[1][0] = 1, dp[1][1] = x[1]+h[1] < x[2];
20 x[n+1] = 1e18;
21 for (int i = 2; i <= n; i++){
22 dp[i][0] = max(dp[i][0], dp[i-1][0]+(x[i]-h[i] > x[i-1]));
23 dp[i][0] = max(dp[i][0], dp[i-1][1]+(x[i]-h[i] > x[i-1]+h[i-1]));
24 dp[i][1] = max(dp[i][1], dp[i-1][1]+(x[i-1]+h[i-1] < x[i] && x[i]+h[i] < x[i+1]));
25 dp[i][1] = max(dp[i][1], dp[i-1][0]+(x[i]+h[i] < x[i+1]));
26 }
27 printf("%d\n", max(dp[n][0], dp[n][1]));
28 return 0;
29 }
431C - k叉树边权1-k,和为n且有一条不小于d的边权的路径数
背包,dp[i][0/1]边权为i,最大值是否大于d
1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 #include <algorithm>
5 #include <vector>
6 #define LL long long
7 #define INF 0x3f3f3f3f
8 #define debug(x) cout << #x << " = " << x << endl;
9 using namespace std;
10
11 const int mx = 110;
12 const int mod = 1e9+7;
13 LL dp[mx][2];
14
15 int main(){
16 int n, k, d;
17 scanf("%d%d%d", &n, &k, &d);
18 //dp[w][0/1]
19 dp[0][0] = 1;
20 for (int i = 1; i <= n; i++){
21 for (int j = 1; j <= k; j++){
22 if (i < j) break;
23 dp[i][1] += dp[i-j][1];
24 dp[i][(j >= d)] += dp[i-j][0];
25 dp[i][0] %= mod, dp[i][1] %= mod;
26 }
27 }
28 printf("%lld\n", dp[n][1]);
29 return 0;
30 }
474D - 只能吃1朵红花,或者k的倍数朵白花
。。。居然跟选拔赛我出的题一模一样,背包
1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 #include <algorithm>
5 #define LL long long
6 #define INF 0x3f3f3f3f
7 #define debug(x) cout << #x << " = " << x << endl;
8 using namespace std;
9
10 const int mx = 1e5+7;
11 const int mod = 1e9+7;
12 LL sum[mx], dp[mx];
13
14 int main(){
15 int t, k, a, b;
16 scanf("%d%d", &t, &k);
17 //dp[i] = dp[i-1]+dp[i-k]
18 dp[0] = 1;
19 for (int i = 1; i < k; i++)
20 dp[i] = 1, sum[i] = sum[i-1]+1;
21 for (int i = k; i < mx; i++)
22 dp[i] = (dp[i-1]+dp[i-k])%mod, sum[i] = (sum[i-1]+dp[i])%mod;
23 while (t--){
24 scanf("%d%d", &a, &b);
25 printf("%lld\n", (sum[b]-sum[a-1]+mod)%mod);
26 }
27 return 0;
28 }
414B - 构造1-n内长为k,后一个数是前一个数倍数的数组方案
dp[i][j]表示前i个数最后一位放j
1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 #include <algorithm>
5 #include <vector>
6 #define LL long long
7 #define INF 0x3f3f3f3f
8 #define debug(x) cout << #x << " = " << x << endl;
9 using namespace std;
10
11 const int mx = 2010;
12 const int mod = 1e9+7;
13 LL dp[mx][mx];
14
15 int main(){
16 int n, k;
17 scanf("%d%d", &n, &k);
18 for (int i = 1; i <= n; i++) dp[1][i] = 1;
19 for (int i = 2; i <= k; i++){
20 for (int j = 1; j <= n; j++){
21 for (int s = 1; s*s <= j; s++){
22 if (j % s != 0) continue;
23 dp[i][j] += dp[i-1][s];
24 if (s*s != j) dp[i][j] += dp[i-1][j/s];
25 dp[i][j] %= mod;
26 //cout << i << " " << j << " " << s << " " << dp[i][j] << endl;
27 }
28 }
29 }
30 LL ans = 0;
31 for (int i = 1; i <= n; i++)
32 ans = (ans + dp[k][i]) % mod;
33 printf("%lld\n", ans);
34 return 0;
35 }
166E - 四面体走n步回到原点的方案
dp[i][j] 第i步在j点,16n滚动数组卡着时限过,有递推公式n解
1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 #include <algorithm>
5 #include <vector>
6 #define LL long long
7 #define INF 0x3f3f3f3f
8 #define debug(x) cout << #x << " = " << x << endl;
9 using namespace std;
10
11 const int mod = 1e9+7;
12 LL dp[2][4];
13
14 void upd(int c, int t){
15 for (int i = 0; i < 4; i++){
16 if (i == c) continue;
17 dp[t^1][c] += dp[t][i];
18 dp[t^1][c] %= mod;
19 }
20 }
21
22 int main(){
23 int n, t = 1;
24 scanf("%d", &n);
25 dp[1][0] = 1;
26 for (int i = 1; i <= n; i++){
27 for (int j = 0; j < 4; j++) upd(j, t);
28 memset(dp[t], 0, sizeof dp[t]);
29 t ^= 1;
30 }
31 printf("%lld\n", dp[t][0]);
32 return 0;
33 }
706C - n个字符串可以反转,改成字典序的花费
dp[i][0/1] 前i个字符串当前反/不反
1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 #include <algorithm>
5 #include <vector>
6 #define LL long long
7 #define INF 0x3f3f3f3f3f3f3f3f
8 #define debug(x) cout << #x << " = " << x << endl;
9 using namespace std;
10
11 const int mx = 1e5+7;
12 struct node{
13 int num;
14 string a, b;
15 }s[mx];
16 LL dp[mx][2];
17
18 int main(){
19 int n;
20 cin >> n;
21 for (int i = 1; i <= n; i++) cin >> s[i].num;
22 for (int i = 1; i <= n; i++){
23 cin >> s[i].a;
24 s[i].b.assign(s[i].a.rbegin(), s[i].a.rend());
25 dp[i][0] = dp[i][1] = INF;
26 }
27 dp[1][0] = 0, dp[1][1] = s[1].num;
28 for (int i = 2; i <= n; i++){
29 if (s[i].a >= s[i-1].a) dp[i][0] = min(dp[i][0], dp[i-1][0]);
30 if (s[i].a >= s[i-1].b) dp[i][0] = min(dp[i][0], dp[i-1][1]);
31 if (s[i].b >= s[i-1].a) dp[i][1] = min(dp[i][1], dp[i-1][0]+s[i].num);
32 if (s[i].b >= s[i-1].b) dp[i][1] = min(dp[i][1], dp[i-1][1]+s[i].num);
33 }
34 LL ans = min(dp[n][0], dp[n][1]);
35 printf("%lld\n", ans == INF ? -1 : ans);
36 return 0;
37 }
676C - 长度为n的ab字符串可以改k个字符,最长连续相同段
前缀和,二分左端点
1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 #include <algorithm>
5 #include <vector>
6 #define LL long long
7 #define INF 0x3f3f3f3f
8 #define debug(x) cout << #x << " = " << x << endl;
9 using namespace std;
10
11 const int mx = 1e5+7;
12 char s[mx];
13 int sum[2][mx];
14
15 int main(){
16 int n, k;
17 scanf("%d%d%s", &n, &k, s+1);
18 for (int i = 1; i <= n; i++){
19 sum[0][i] = sum[0][i-1]+(s[i] == 'a');
20 sum[1][i] = sum[1][i-1]+(s[i] == 'b');
21 }
22 int ans = 0;
23 for (int i = 1; i <= n; i++){
24 int x = upper_bound(sum[0]+1, sum[0]+n+1, sum[0][i]+k-(s[i]=='a'))-sum[0]-1;
25 ans = max(ans, x-i+1);
26 x = upper_bound(sum[1]+1, sum[1]+n+1, sum[1][i]+k-(s[i]=='b'))-sum[1]-1;
27 ans = max(ans, x-i+1);
28 }
29 printf("%d\n", ans);
30 return 0;
31 }
446A - n个数能改变一个,求最长递增子串
搞一下左边有多少比它小的,右边有多少比它大的枚举
1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 #include <algorithm>
5 #include <vector>
6 #define LL long long
7 #define INF 0x3f3f3f3f
8 #define debug(x) cout << #x << " = " << x << endl;
9 using namespace std;
10
11 const int mx = 1e5+7;
12 int a[mx], l[mx], r[mx];
13
14 int main(){
15 int n;
16 scanf("%d", &n);
17 for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
18 if (n <= 2){
19 printf("%d\n", n);
20 return 0;
21 }
22 for (int i = 2; i <= n; i++){
23 if (a[i] > a[i-1]) l[i] = l[i-1]+1;
24 else l[i] = 0;
25 }
26 for (int i = n-1; i >= 1; i--) {
27 if (a[i] < a[i+1]) r[i] = r[i+1]+1;
28 else r[i] = 0;
29 }
30 int ans = 0;
31 ans = max(ans, l[n-1]+2);
32 ans = max(ans, r[2]+2);
33 for (int i = 2; i < n; i++){
34 int sum = max(l[i-1], r[i+1]);
35 if (a[i-1]+1 < a[i+1]) sum += min(l[i-1], r[i+1])+1;
36 ans = max(ans, sum+2);
37 }
38 printf("%d\n", ans);
39 return 0;
40 }
2019.3.14 先回去了,今天没发现很有收获的题,水题就必须每天多写几题吧
467C - 用k个长度为m不重合的区间覆盖n的数组,求最大价值
dp[i][j] 前i个数字用了j个区间
Java课上皮了一下偷偷刷题,代码没啥区别
1 import java.util.Scanner;
2
3 public class Main {
4 public static void main(String[] args){
5 final int MX = 5010;
6 Scanner sc = new Scanner(System.in);
7 int n = sc.nextInt(), m = sc.nextInt(), k = sc.nextInt(), a;
8 long[] sum = new long[MX];
9 for (int i = 1; i <= n; i++){
10 a = sc.nextInt();
11 sum[i] = sum[i-1]+a;
12 }
13 long[][] dp = new long[MX][MX];
14 for (int i = 1; i <= n; i++){
15 for (int j = 1; j <= k; j++){
16 dp[i][j] = dp[i-1][j];
17 if (i >= m)
18 dp[i][j] = Math.max(dp[i][j], dp[i-m][j-1]+sum[i]-sum[i-m]);
19 }
20 }
21 System.out.println(dp[n][k]);
22 }
23 }
118D - 1有n个,2有m个,1最多连续放a个,2最多连续放b个
dp[i][j][0/1] 1有i个2有j个,最后一个是1/2的方案数,取模坑了一发。。
一开始状态定义对了,后来某个地方写搓了让我误以为状态是错的。。。最近几题几乎都是无脑直觉定状态居然还一路对过来了qwq
还是畏难情绪太严重,其实这些都是水题的。。。开上限到2k了
1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 #include <algorithm>
5 #include <vector>
6 #define LL long long
7 #define INF 0x3f3f3f3f
8 #define debug(x) cout << #x << " = " << x << endl;
9 using namespace std;
10
11 const int mod = 1e8;
12 const int mx = 110;
13 LL dp[mx][mx][2];
14
15 int main(){
16 int n, m, a, b;
17 scanf("%d%d%d%d", &n, &m, &a, &b);
18 for (int i = 0; i <= a; i++) dp[i][0][0] = 1;
19 for (int i = 0; i <= b; i++) dp[0][i][1] = 1;
20 for (int i = 1; i <= n; i++){
21 for (int j = 1; j <= m; j++){
22 for (int k = 1; k <= a && i-k >= 0; k++){
23 dp[i][j][0] += dp[i-k][j][1];
24 dp[i][j][0] %= mod;
25 }
26 for (int k = 1; k <= b && j-k >= 0; k++){
27 dp[i][j][1] += dp[i][j-k][0];
28 dp[i][j][1] %= mod;
29 }
30 }
31 }
32 printf("%lld\n", (dp[n][m][0]+dp[n][m][1])%mod);
33 return 0;
34 }
788A - dp[i][0/1]表示选第i个数,是奇数/偶数项的最大值
1 #include <bits/stdc++.h>
2 #define LL long long
3 #define INF 0x3f3f3f3f
4 #define INFLL 0x3f3f3f3f3f3f3f3f
5 #define debug(x) cout << #x << " = " << x << endl;
6 #define lid id << 1
7 #define rid id << 1 | 1
8 using namespace std;
9
10 const int mx = 1e5+7;
11 int a[mx];
12 LL dp[mx][2];
13
14 int main(){
15 int n;
16 scanf("%d", &n);
17 for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
18 for (int i = 1; i < n; i++) a[i] = abs(a[i]-a[i+1]);
19 LL ans = 0;
20 for (int i = 1; i < n; i++){
21 dp[i][0] = max(dp[i][0], dp[i-1][1]+a[i]);
22 dp[i][1] = max(dp[i][1], dp[i-1][0]-a[i]);
23 ans = max(ans, max(dp[i][0], dp[i][1]));
24 }
25 printf("%lld\n", ans);
26 return 0;
27 }
534B - 初速度,加速度和末速度求最大位移
dp[i][j]第i时刻速度为j
1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 #include <algorithm>
5 #define LL long long
6 #define INF 0x3f3f3f3f
7 #define debug(x) cout << #x << " = " << x << endl;
8 using namespace std;
9
10 const int mx = 110;
11 int dp[mx][mx*10];
12
13 int main(){
14 int vl, vr, t, d;
15 scanf("%d%d%d%d", &vl, &vr, &t, &d);
16 //dp[i][j] = max(dp[i-1][k] + k)
17 memset(dp, -1, sizeof dp);
18 dp[1][vl] = vl;
19 for (int i = 1; i <= t; i++){
20 for (int j = 0; j <= 1000; j++){
21 if (dp[i][j] == -1) continue;
22 for (int k = max(0, j-d); k <= j+d; k++)
23 dp[i+1][k] = max(dp[i+1][k], dp[i][j]+k);
24 }
25 }
26 printf("%d\n", dp[t][vr]);
27 return 0;
28 }
567C - 公比为k的等比数列数量
k定下来就可以map暴力搞
1 #include <bits/stdc++.h>
2 #define LL long long
3 #define INF 0x3f3f3f3f
4 #define INFLL 0x3f3f3f3f3f3f3f3f
5 #define debug(x) cout << #x << " = " << x << endl;
6 using namespace std;
7
8 const int mx = 1e5+7;
9 map<int, LL> dp[4];
10
11 int main(){
12 int n, k, a;
13 scanf("%d%d", &n, &k);
14 LL ans = 0;
15 //dp[i][j]第i-1项,数字为j
16 for (int i = 1; i <= n; i++){
17 scanf("%d", &a);
18 if (a % k == 0){
19 ans += dp[2][a/k];
20 dp[2][a] += dp[1][a/k];
21 }
22 dp[1][a]++;
23 }
24 printf("%lld\n", ans);
25 return 0;
26 }
553A - 组合数 这里有个线性推逆元的方法
1 #include <bits/stdc++.h>
2 #define LL long long
3 #define INF 0x3f3f3f3f
4 #define INFLL 0x3f3f3f3f3f3f3f3f
5 #define debug(x) cout << #x << " = " << x << endl;
6 using namespace std;
7
8 const int mod = 1e9+7;
9 const int mx = 1e6;
10 int a[1010];
11 LL fac[mx+5], inv[mx+5];
12
13 void init(){
14 fac[0] = 1;
15 for (int i = 1; i <= mx; i++) fac[i] = fac[i-1]*i%mod;
16 inv[1] = 1;
17 for (int i = 2; i <= mx; i++) inv[i] = mod-(mod/i)*inv[mod%i]%mod;
18 inv[0] = 1;
19 for (int i = 1; i <= mx; i++) inv[i] = inv[i]*inv[i-1]%mod;
20 }
21
22 LL C(int n, int m){
23 return fac[n]*inv[m]%mod*inv[n-m]%mod;
24 }
25
26 int main(){
27 init();
28 int n, sum = 0;
29 scanf("%d", &n);
30 for (int i = 1; i <= n; i++) {
31 scanf("%d", &a[i]);
32 sum += a[i];
33 }
34 LL ans = 1;
35 for (int i = n; i >= 1; i--){
36 ans = ans*C(sum-1, a[i]-1)%mod;
37 sum -= a[i];
38 }
39 printf("%lld\n", ans);
40 return 0;
41 }
607A - dp[i]表示i后面的全部破坏,前面会被破坏的数量
1 #include <bits/stdc++.h>
2 #define LL long long
3 #define INF 0x3f3f3f3f
4 #define INFLL 0x3f3f3f3f3f3f3f3f
5 #define debug(x) cout << #x << " = " << x << endl;
6 using namespace std;
7
8 const int mx = 1e5+7;
9 struct node{
10 int x, y;
11 bool operator < (const node& c) const {
12 return x < c.x;
13 }
14 }a[mx];
15 int dp[mx];
16
17 int main(){
18 int n;
19 scanf("%d", &n);
20 for (int i = 1; i <= n; i++) {
21 scanf("%d%d", &a[i].x, &a[i].y);
22 }
23 sort(a+1, a+n+1);
24 int ans = INF;
25 for (int i = 1; i <= n; i++){
26 int k = lower_bound(a+1, a+n+1, node{a[i].x-a[i].y, 0})-a-1;
27 dp[i] = dp[k]+i-k-1;
28 ans = min(ans, dp[i]+n-i);
29 }
30 printf("%d\n", ans);
31 return 0;
32 }
603A - dp[i][0/1/2][0/1]表示前i个字符翻转的状态为j数字为k时的最大长度
1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 #include <algorithm>
5 #include <map>
6 #define LL long long
7 #define INF 0x3f3f3f3f
8 #define debug(x) cout << #x << " = " << x << endl;
9 using namespace std;
10
11 const int mx = 1e5+7;
12 char s[mx];
13 int dp[mx][3][2];
14
15 int main(){
16 int n, ans = 0;
17 scanf("%d%s", &n, s+1);
18 for (int i = 1; i <= n; i++){
19 int c = s[i]-'0';
20 memcpy(dp[i], dp[i-1], sizeof dp[i]);
21 for (int j = 0; j < 3; j++){
22 for (int k = 0; k < 2; k++) {
23 if (k != c)
24 dp[i][j][c] = max(dp[i][j][c], dp[i-1][j][k]+1);
25 else if (j)
26 dp[i][j][k] = max(dp[i][j][k], dp[i-1][j-1][k]+1);
27 }
28 }
29 }
30 for (int i = 0; i < 3; i++)
31 for (int j = 0; j < 2; j++)
32 ans = max(ans, dp[n][i][j]);
33 printf("%d\n", ans);
34 return 0;
35 }
577B - 抽屉原理,然后就是n方的裸dp,滚动数组(感觉memcpy的方法真的好写
1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 #include <algorithm>
5 #define LL long long
6 #define INF 0x3f3f3f3f
7 #define debug(x) cout << #x << " = " << x << endl;
8 using namespace std;
9
10 const int mx = 1e6+7;
11 int dp[2][1010];
12 int a[mx];
13
14 int main(){
15 int n, m;
16 scanf("%d%d", &n, &m);
17 for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
18 if (n >= m){
19 printf("YES\n");
20 return 0;
21 }
22 for (int i = 1; i <= n; i++){
23 for (int j = 0; j < m; j++) dp[1][j] = 0;
24 dp[1][a[i]%m] = 1;
25 for (int j = 0; j < m; j++){
26 if (dp[1][0]) break;
27 if (a[i] % m == j) continue;
28 dp[1][j] = max(dp[0][j], dp[0][(j-a[i]%m+m)%m]);
29 }
30 memcpy(dp[0], dp[1], sizeof dp[0]);
31 }
32 printf("%s\n", dp[0][0] ? "YES" : "NO");
33 return 0;
34 }
264B - 设dp[i]为结尾的数字质因数有i的最大长度(可以看做是对于每一位ai的质因数做LIS
1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 #include <algorithm>
5 #define LL long long
6 #define INF 0x3f3f3f3f
7 #define debug(x) cout << #x << " = " << x << endl;
8 using namespace std;
9
10 const int mx = 1e5+7;
11 int a[mx], prime[mx];
12 int dp[mx];
13 bool vis[mx];
14 int tot = 0;
15
16 void init(int n){
17 vis[1] = 1;
18 for (int i = 2; i <= n; i++){
19 if (!vis[i]) prime[++tot] = i;
20 for (int j = 1; j <= tot && 1ll*i*prime[j] <= n; j++){
21 vis[i*prime[j]] = 1;
22 if (i % prime[j] == 0) break;
23 }
24 }
25 }
26
27 int main(){
28 init(100000);
29 int n, x, ans = 0;
30 scanf("%d", &n);
31 for (int i = 1; i <= n; i++) {
32 scanf("%d", &a[i]);
33 if (n == 1){
34 printf("1\n");
35 return 0;
36 }
37 x = a[i];
38 int tmp = 0;
39 for (int j = 1; j <= tot && j*j <= x; j++){
40 if (x % prime[j] != 0) continue;
41 while (x % prime[j] == 0) x /= prime[j];
42 tmp = max(tmp, dp[prime[j]]+1);
43 }
44 if (x > 1) tmp = max(tmp, dp[x]+1);
45 x = a[i];
46 for (int j = 1; j <= tot && j*j <= x; j++){
47 if (x % prime[j] != 0) continue;
48 while (x % prime[j] == 0) x /= prime[j];
49 dp[prime[j]] = tmp;
50 }
51 if (x > 1) dp[x] = tmp;
52 ans = max(ans, tmp);
53 }
54 printf("%d\n", ans);
55 return 0;
56 }
225B- dp[i][j][0/1]表示前i列前面连续了j列相同,当前列是0/1的最小代价, 预处理代价然后刷表, 最后在合法范围内找答案
1 #include <bits/stdc++.h>
2 #define INF 0x3f3f3f3f
3 #define debug(x) cout << #x << " = " << x << endl;
4 #define lid id << 1
5 #define rid id << 1 | 1
6 using namespace std;
7 typedef long long LL;
8 typedef pair<int,int> pii;
9 typedef pair<double,double> pdd;
10
11 const int mx = 1010;
12 char s[mx];
13 int a[mx], dp[mx][mx][2];
14
15 int main(){
16 int n, m, x, y;
17 scanf("%d%d%d%d", &n, &m, &x, &y);
18 for (int i = 1; i <= n; i++){
19 scanf("%s", s+1);
20 for (int j = 1; j <= m; j++)
21 if (s[j] == '#') a[j]++;
22 }
23 memset(dp, INF, sizeof dp);
24 dp[1][1][0] = a[1];
25 dp[1][1][1] = n-a[1];
26 for (int i = 1; i < m; i++){
27 for (int j = 1; j <= y; j++){
28 if (dp[i][j][0] != INF){
29 if (j >= x) dp[i+1][1][1] = min(dp[i+1][1][1], dp[i][j][0] + n-a[i+1]);
30 dp[i+1][j+1][0] = min(dp[i+1][j+1][0], dp[i][j][0] + a[i+1]);
31 }
32 if (dp[i][j][1] != INF){
33 if (j >= x) dp[i+1][1][0] = min(dp[i+1][1][0], dp[i][j][1] + a[i+1]);
34 dp[i+1][j+1][1] = min(dp[i+1][j+1][1], dp[i][j][1] + n-a[i+1]);
35 }
36 }
37 }
38 int ans = INF;
39 for (int i = x; i <= y; i++){
40 ans = min(ans, dp[m][i][0]);
41 ans = min(ans, dp[m][i][1]);
42 }
43 printf("%d\n", ans);
44 return 0;
45 }
来源:oschina
链接:https://my.oschina.net/u/4366606/blog/3612928