关于一些水题,思维题,套路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 ", 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 ", 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 ", 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 ", 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 ", 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 ", (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 ", 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 ", 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 ", 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 ", 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); 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 ", 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 ", (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 ", 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 ", 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 ", 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 ", 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 ", 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 ", 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 "); 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 ", 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 "); 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 ", 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 ", ans); 44 return 0; 45 }