《5.9训练部分题解》
A:没写。
B:没写。
C:
m个块来考虑,假设当前为[1,m]位置都站满了。
现在我们要到[2,m + 1],如果a[1] > a[m + 1],跳过去之后a[m + 1]被站满。
如果a[1] < a[m + 1]那么跳过去没被站满,那么剩下的只能有[2,m]来填充。
那么综上所诉我们的答案就是所以m个块的和的最小值。
#include <bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int, int> pii; const int N = 1e6 + 5; const int M = 2000 + 5; const LL Mod = 10007; #define pi acos(-1) #define INF 1e18 #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO { inline LL read() { LL x = 0, f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') { x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); } return x * f; } } using namespace FASTIO; LL a[N]; int main() { int n,m;n = read(),m = read(); for(int i = 1;i < n;++i) a[i] = read(); LL sum = 0; for(int i = 1;i <= m;++i) sum += a[i]; LL ans = sum; for(int i = m + 1;i < n;++i) { sum -= a[i - m]; sum += a[i]; ans = min(ans,sum); } printf("%lld\n",ans); return 0; }
D:
dp[i][j][k] - 到i修改了j次,第i个位置以k为结尾的最优解
枚举前一个位置是什么然后转移即可。
注意用滚动数组压缩空间。
#include <bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int, int> pii; const int N = 1e5 + 5; const int M = 350; const LL Mod = 1e9 + 7; #define pi acos(-1) #define INF 1e9 #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO { inline LL read() { LL x = 0, f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') { x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); } return x * f; } } using namespace FASTIO; int dp[2][505][30];//dp[i][j][k] - 到i修改了j次,第i个位置以k为结尾的最优解 int main() { int n,t; n = read(),t = read(); string s;cin >> s; memset(dp,0x3f3f3f,sizeof(dp)); for(int k = 0;k < 26;++k) { int x = s[0] - 'a'; if(x == k) { dp[1][0][x] = 1; } else { dp[1][1][k] = 1; } } for(int i = 2;i <= n;++i) { memset(dp[i % 2],0x3f3f3f,sizeof(dp[i % 2])); for(int j = 0;j <= t;++j) { if(j > t) break; int x = s[i - 1] - 'a'; for(int k = 0;k < 26;++k) { if(x == k) { dp[i % 2][j][k] = min(dp[i % 2][j][k],dp[(i + 1) % 2][j][k]); } else { if(j > 0) { dp[i % 2][j][k] = min(dp[i % 2][j][k],dp[(i + 1) % 2][j - 1][k]); } dp[i % 2][j][x] = min(dp[i % 2][j][x],dp[(i + 1) % 2][j][k] + 1); } } } } int ans = INF; for(int j = 0;j <= t;++j) { for(int k = 0;k < 26;++k) { ans = min(ans,dp[n % 2][j][k]); } } printf("%d\n",ans); // system("pause"); return 0; }
E:
对于每个数只有三种操作,1-加入总和,2-变阶乘后加入总和,3-不加入总和。
那么复杂度就是3^n,显然这里会TLE,我们折半搜,先算前半部分,然后map存值。
再搜后半部分顺便统计答案,复杂度3^(n / 2)
#include <bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<LL, int> pii; const int N = 1e6 + 5; const int M = 2000 + 5; const LL Mod = 10007; #define pi acos(-1) #define INF 1e18 #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO { inline LL read() { LL x = 0, f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') { x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); } return x * f; } } using namespace FASTIO; int n,k; LL s,ans = 0,f[20],a[30],dp[30][30]; map<LL,int> mp[30]; void init() { f[1] = 1; for(int i = 2;i <= 19;++i) f[i] = f[i - 1] * i; } void dfs(int x,int num,LL sum) { if(x == n / 2 + 1) { // printf("%d %lld\n",k - num,sum); mp[k - num][sum]++; return ; } if(sum + a[x] <= s) dfs(x + 1,num,sum + a[x]); if(a[x] <= 19 && sum + f[a[x]] <= s && num > 0) dfs(x + 1,num - 1,sum + f[a[x]]); dfs(x + 1,num,sum + 0); } void dfs2(int x,int num,LL sum) { if(x == n + 1) { for(int i = 0;i <= num;++i) { ans += mp[i][s - sum]; } return ; } if(sum + a[x] <= s) dfs2(x + 1,num,sum + a[x]); if(a[x] <= 19 && sum + f[a[x]] <= s && num > 0) dfs2(x + 1,num - 1,sum + f[a[x]]); dfs2(x + 1,num,sum + 0); } int main() { init(); n = read(),k = read(),s = read(); for(int i = 1;i <= n;++i) a[i] = read(); dfs(1,k,0); dfs2(n / 2 + 1,k,0); printf("%lld\n",ans); // system("pause"); return 0; } /* 2 4 2 2 2 */
F:
枚举第i位是什么数,然后dfs判断一下最大值。
假设我们现在能取到的最大值是x,然后我们现在枚举的数是a[i],那么我们下一个枚举的数的范围肯定是a[i] ~ x + 1。
#include <bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<LL, int> pii; const int N = 1e3 + 5; const int M = 2000 + 5; const LL Mod = 10007; #define pi acos(-1) #define INF 1e18 #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO { inline LL read() { LL x = 0, f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') { x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); } return x * f; } } using namespace FASTIO; int n,m,ans,a[15],dp[N],tmp[N]; void dfs(int x,int num,int sum,int limit) { dp[sum] = 1; if(x == limit) return ; for(int i = 0;i <= num;++i) { dfs(x + 1,num - i,sum + a[x] * i,limit); } } void solve(int x) { memset(dp,0,sizeof(dp)); //for(int i = 1;i < x;++i) printf("%d%c",a[i],i == x - 1 ? '\n' : ' '); dfs(1,m,0,x); int L = a[x - 1] + 1,r; for(int i = 1;;++i) { if(dp[i] == 0) { r = i; break; } } if(r - 1 > ans) { for(int i = 1;i < x;++i) tmp[i] = a[i]; ans = r - 1; } if(x == n + 1 || r < L) return ; for(int i = L;i <= r;++i) { a[x] = i; solve(x + 1); } } int main() { n = read(),m = read(); a[1] = 1; ans = 1; solve(2); for(int i = 1;i <= n;++i) printf("%d%c",tmp[i],i == n ? '\n' : ' '); printf("%d\n",ans); return 0; }
G:简单题
H:
首先,这里除了两个对角线之外出发都是组成环。并且这些环都可以看成从第一行的某个位置出发形成的环。
那么我们环的总个数就是n - 2 加上两个对角线2.一共只有n种不同性质的走法。
所以我们可以n^2枚举两个人的走法。注意在处理走法的时候同时处理一下重复的位置。
#include <bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<LL, int> pii; const int N = 1e5 + 5; const int M = 2000 + 5; const LL Mod = 10007; #define pi acos(-1) #define INF 1e9 #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO { inline LL read() { LL x = 0, f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') { x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); } return x * f; } } using namespace FASTIO; int n,a[1005][1005],sum[1005],dir[1005][1005][5]; int lp[1005][1005]; bool vis[1005][1005]; int main() { n = read(); for(int i = 1;i <= n;++i) for(int j = 1;j <= n;++j) a[i][j] = read(); for(int i = 1;i <= n;++i) { int nowx = 1,nowy = i,cx = 1,cy = 1,id = 1; if(i == n) cx = 1,cy = -1,id = 2; memset(vis,0,sizeof(vis)); while(vis[nowx][nowy] == 0) { sum[i] += a[nowx][nowy]; vis[nowx][nowy] = 1; dir[nowx][nowy][id] = i; for(int j = 1;j <= 4;++j) { lp[i][dir[nowx][nowy][j]] += a[nowx][nowy]; lp[dir[nowx][nowy][j]][i] += a[nowx][nowy]; } if(nowx == n && nowy == n) break; if(nowx == n && nowy == 1) break; nowx += cx,nowy += cy; if(nowy == n) { cx = 1,cy = -1; id = 2; } if(nowx == n) { cx = -1,cy = -1; id = 3; } if(nowx == 1) { cx = 1,cy = 1; id = 1; } if(nowy == 1) { cx = -1,cy = 1; id = 4; } } } int ans = 0; //or(int i = 1;i <= n;++i) printf("%d\n",sum[i]); for(int i = 1;i <= n;++i) { for(int j = i + 1;j <= n;++j) { ans = max(ans,sum[i] + sum[j] - lp[i][j]); } } printf("%d\n",ans); // system("pause"); return 0; }
I:
可搜索可转压。
我这里用了状压。
dp[i][j]表示i状态下j营养的数量。
转移就每次枚举一位没有的加入即可。
#include <bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int, int> pii; const int N = 5e5 + 5; const int M = 2000 + 5; const LL Mod = 10007; #define pi acos(-1) #define INF 1e18 + 5 #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO { inline int read() { int x = 0, f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') { x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); } return x * f; } } using namespace FASTIO; int a[30],b[20][30],ans[20],p[20],n; int dp[1 << 15][30]; bool check(int x) { for(int i = 1;i <= n;++i) if(dp[x][i] < a[i]) return false; return true; } bool solve(int len) { for(int i = 1;i <= len;++i) { if(p[i] == ans[i]) continue; if(p[i] < ans[i]) return true; else return false; } } int main() { n = read(); for(int i = 1;i <= n;++i) a[i] = read(); int m;m = read(); for(int i = 0;i < m;++i) { for(int j = 1;j <= n;++j) b[i][j] = read(); } for(int i = 0;i < (1 << m);++i) { for(int j = 0;j < m;++j) { int g = ((i >> j) & 1); if(g == 0) { int x = i | (1 << j); for(int k = 1;k <= n;++k) { dp[x][k] = dp[i][k] + b[j][k]; } } } } //for(int i = 0;i < (1 << m);++i) //for(int j = 1;j <= n;++j) printf("dp[%d][%d] is %d\n",i,j,dp[i][j]); int len = 1000; for(int i = 0;i < (1 << m);++i) { if(check(i)) { int x = i,ta = 0; for(int j = 1;j <= m;++j) { if(x % 2 != 0) p[++ta] = j; x /= 2; } if(ta < len) { len = ta; x = i; int f = 0; for(int j = 1;j <= m;++j) { if(x % 2 != 0) ans[++f] = j; x /= 2; } } else if(ta == len && solve(len)) { x = i; int f = 0; for(int j = 1;j <= m;++j) { if(x % 2 != 0) ans[++f] = j; x /= 2; } } } } printf("%d",len); for(int i = 1;i <= len;++i) printf(" %d",ans[i]); return 0; } /* 4 1250 200 300 400 5 100 200 300 400 900 150 389 399 200 300 200 300 50 50 50 50 500 120 150 300 */
H:bfs即可。
hash一下数字的状态来节省空间。
#include <bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int, int> pii; const int N = 5e5 + 5; const int M = 2000 + 5; const LL Mod = 10007; #define pi acos(-1) #define INF 1e18 + 5 #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO { inline int read() { int x = 0, f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') { x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); } return x * f; } } using namespace FASTIO; map<int,int> mp; int st,cnt = 0,pos0,b[4][2] = {1,0,-1,0,0,1,0,-1},a[10]; struct Node{ int x,step,pos; }; int cal(int x) { if(x <= 3) return 1; else if(x <= 6) return 2; else return 3; } int cal2(int x) { if(x % 3 == 0) return 3; else return x % 3; } int cha(int x,int y) { int ma = 0; if(x == 1) ma += 0; else if(x == 2) ma += 3; else ma += 6; ma += y; return ma; } int bfs() { queue<Node> Q; Q.push(Node{st,0,pos0}); while(!Q.empty()) { Node q = Q.front(); Q.pop(); if(q.x == 123804765) return q.step; int nowx = cal(q.pos),nowy = cal2(q.pos); int ta = q.x; //printf("ta is %d pos is %d\n",ta,q.pos); for(int i = 9;i >= 1;--i) a[i] = ta % 10,ta /= 10; for(int i = 0;i < 4;++i) { int px = nowx + b[i][0]; int py = nowy + b[i][1]; if(px >= 1 && px <= 3 && py >= 1 && py <= 3) { int ma = cha(px,py); swap(a[q.pos],a[ma]); int tmp = 0; for(int i = 1;i <= 9;++i) tmp = tmp * 10 + a[i]; if(mp[tmp] == 0) { mp[tmp] = ++cnt; Q.push(Node{tmp,q.step + 1,ma}); } swap(a[q.pos],a[ma]); } } } } int main() { st = read(); mp[st] = ++cnt; int i = 9,ff = st; while(ff) { if(ff % 10 == 0) { pos0 = i; break; } ff /= 10; i--; } printf("%d\n",bfs()); return 0; }