这个题目的意思是,把这个n的序列分成三个连续的部分,要求这三个部分的和是一样的。问这种划分的方法有多少种。
这个题目和之前写过的数字划分有点像,这个就是要先进行前缀和的处理,然后找到s/3 和 2*s/3 这两个位置。
因为这个有负数,所以有可能出现,2*s/3 的位置在 s/3 的位置之后,所以这个时候就需要进行处理。
我们每一个 s/3 去找到 2*s/3 的所有合法位置即可。
#include <cstdio> #include <iostream> #include <cstdlib> #include <cstring> #include <algorithm> #include <queue> #include <vector> #define inf 0x3f3f3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; typedef long long ll; const int maxn = 5e5 + 10; ll a[maxn], sum[maxn]; int x[maxn], y[maxn]; int main() { int n; ll S = 0; scanf("%d", &n); for(int i=1;i<=n;i++) { scanf("%lld", &a[i]); sum[i] = sum[i - 1] + a[i]; S += a[i]; } if (S % 3 != 0) { printf("0 "); return 0; } S /= 3; int tot = 0, cnt = 0; for(int i=1;i<n;i++) { if (sum[i] == S) x[tot++] = i; if (sum[i] == 2 * S) y[cnt++] = i; } if(tot==0||cnt==0) { printf("0 "); return 0; } ll ans = 0; for(int i=0;i<tot;i++) { ll len = upper_bound(y, y + cnt, x[i]) - y; ans += (cnt - len); } printf("%lld ", ans); return 0; }
这个题目是一个很简单的线性dp。
题目大意:土拨鼠吃花,对于白花,它只吃数量恰好为k这么多的白花,不然就不吃,它给你一个区间从a到b,表示花的数量从a到b,求土拨鼠吃花的方案数。
这个和之前寒假回来后的选拔赛的dp是一样的,因为这个和顺序也有关,所以要先枚举背包容量,然后再去枚举种类,如果和放入背包的顺序无关,就是先枚举种类再去枚举数量。
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <queue> #include <vector> #define inf 0x3f3ff3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; typedef long long ll; const int maxn = 1e5 + 10; const ll mod = 1e9 + 7; ll dp[maxn]; ll sum[maxn]; int main() { int t, k; scanf("%d%d", &t, &k); dp[0] = 1; for (int i = 1; i <= maxn; i++) { if (i >= k) { dp[i] = dp[i - 1] + dp[i - k]; dp[i] %= mod; } else { dp[i] = dp[i - 1]; dp[i] %= mod; } } for(int i=1;i<=maxn;i++) { sum[i] = sum[i - 1] + dp[i]; sum[i] %= mod; } while(t--) { int a, b; scanf("%d%d", &a, &b); ll ans = (sum[b] - sum[a - 1] + mod) % mod; printf("%lld ", ans); } return 0; }
题目大意:您的任务是找到a的最长子段,这样可以从子段中最多更改一个数字(将一个数字更改为您想要的任何整数),以使子段严格增加。
这个就是处理一下 对于第 i 个值,求出以 i 为起点的递增序列的长度,以 i 为终点的递增序列长度。
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <queue> #include <vector> #define inf 0x3f3ff3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; typedef long long ll; const int maxn = 1e5 + 10; ll a[maxn], dp1[maxn], dp2[maxn]; int main() { int n; scanf("%d", &n); a[0] = -inf; for (int i = 1; i <= n; i++) { scanf("%lld", &a[i]); dp1[i] = 1; dp2[i] = 1; } ll mx = 0; for (int i = 2; i <= n; i++) { if (a[i] > a[i - 1]) dp1[i] = dp1[i - 1] + 1; mx = max(dp1[i], mx); } for (int i = n - 1; i >= 1; i--) { if (a[i] < a[i + 1]) dp2[i] = dp2[i + 1] + 1; //printf("dp2[%d]=%lld ", i, dp2[i]); } ll ans = 1; for(int i=1;i<=n;i++) { if (a[i - 1] <= a[i + 1] - 2) ans = max(ans, dp1[i - 1] + dp2[i + 1] + 1); } if (mx < n) mx++; ans = max(ans, mx); printf("%lld ", ans); return 0; }
这个题目我觉得有点难,就是找到一个长度恰好为m的k个区间,然后这k个区间求和,使得和最大。
这个n,m,k都比较小,所以可以定义一个二维的,这个和之前的奶牛的题目有点类似 https://www.cnblogs.com/EchoZQN/p/11043552.html
这个是lj给了我这个dp状态的定义,我才写出来转移方程的
dp[i][j] 表示前面 i 个数,选了j个区间的最大和。
所以这个转移方程就是 如果我们选了第i个数 那么 dp[i][j]=max(dp[i-m][j-1],dp[i][j])
如果我们不选第 i 个数 那么 dp[i][j]=max(dp[i][j],dp[i-1][j])
这个都写出来了,就很好写了。
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <queue> #include <vector> #define inf 0x3f3ff3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; typedef long long ll; const int maxn = 1e5 + 10; ll sum[maxn], a[maxn], dp[5005][5005]; int main() { int n, m, k; scanf("%d%d%d", &n, &m, &k); for (int i = 1; i <= n; i++) { scanf("%lld", &a[i]); sum[i] = sum[i - 1] + a[i]; } for(int i=1;i<=n;i++) { for(int j=1;j<=k;j++) { if (i >= m) { dp[i][j] = max(dp[i - m][j - 1] + sum[i] - sum[i - m], dp[i][j]); dp[i][j] = max(dp[i - 1][j], dp[i][j]); } else dp[i][j] = dp[i - 1][j]; } } printf("%lld ", dp[n][k]); return 0; }
这个题目不是很难,但是需要想一想。
首先,我们优先考虑这个数的长度,然后再考虑这个数的大小。
所以我们可以先由这个最小的数求出长度,然后再去找这个长度如果不整除,那就尽量选更大的。
#include <cstdio> #include <iostream> #include <cstdlib> #include <cstring> #include <algorithm> #include <queue> #include <vector> #define inf 0x3f3f3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; typedef long long ll; const int maxn = 1e6 + 10; int b[maxn]; int a[15]; int main() { int V; scanf("%d", &V); int mn = inf; for (int i = 1; i <= 9; i++) { scanf("%d", &a[i]); mn = min(mn, a[i]); } if (V < mn) { printf("-1 "); return 0; } //printf("mn=%d ", mn); int tot = 0; int len = V / mn; int M = V % mn; int mx = mn + M; while(len--) { //printf("len=%d mx=%d ", len, mx); int flag = 0; for(int i=9;i>=1;i--) { if(a[i]<=mx) { flag = i; b[tot++] = i; break; } } mx -= (a[flag] - mn); } for (int i = 0; i < tot; i++) printf("%d", b[i]); printf(" "); return 0; }