2021.11.4
上午模拟赛 50+10+0+0
第一题贪心写法
T、2
注意到要求的是距离的最⼩值的最⼤值。 ⽐较容易想到的是⼆分答案 x, 判定是否能找到⼀条最⼩值不⼩于x的路径。等价于对 每个引⼒柱做⼀个半径为 x 的圆,判定是否能⾛到终点。 在这⼀限制下⼩w不能⾛到的区域,肯定是由若⼲个距离2x的障碍和上下边界组 成。那么实际上就是求最⼩⽣成树上上边界到下边界的路径上最⼤边。需要求 n 个点 n^2 条边的最⼩⽣成树,kruskal 是 n^2logn 的,可以获得 80 分,prim算法 n^2, 期望得到满分。
T4
区间dp+优化
今日学习内容:dp
√1.背包dp 01,完全,多重,分组,依赖性
√2.区间dp 合并石子
3.树形dp
4.状压dp(初状态的确定)
√5.线性dp
√6.棋盘dp
√7.其他常用dp模板:最长上升子序列,最长公共子序列,最大权值正方形,最大全 0/全1正方形,最大连续子段和,期望dp,概率dp
8.dp优化
int lingyibeibao() { for(int i=0; i<n; i++) for(int j=m; j>=w[i]; j--) dp[j]=max(dp[j],dp[j-w[i]]+u[i]); } int wanquanbeibao() { for(int i=0; i<n; i++) for(int j=w[i]; j<=m; j++) dp[j]=max(dp[j],dp[j-w[i]]+u[i]); } int duochongbeibao() { for(int i=0; i<n; i++) for(int k=0; k<p[i]; k++) for(int j=m; j>=w[i]; j--) dp[j]=max(dp[j],dp[j-w[i]]+u[i]); } int fenzubeibao() { for(int i=1; i<=n; i++) for(int j=0; j<=m; j--) for(int k=1; k<=s[i]; k++) //s[i]表示第i组物品的个数 if(j>=v[i][k]) { //剩余的背包容量j大于第i组的第k个物品的体积 f[i][j] = max(f[i][j],f[i-1][j-v[i][k]]+w[i][k]); } } int yilaibeibao() { int dfs(int u) { /*说明是用户*/ if(u>(n-m)) { f[u][1] = val[u]; return 1;//用户个数 } int sum = 0,now; for(int i=head[u]; i!=-1; i=edge[i].next) { int v = edge[i].v; now = dfs(v);//以v为根节点的子树有多少个用户 sum+=now; for(int j=sum; j>=0; j--) for(int k=1; k<=now; k++) { if(j>=k) f[u][j] = max(f[u][j],f[u][j-k]+f[v][k]-edge[i].w);//edge[i].w是u到v的花费 } } return sum; } } int qvjiandp() { for(int len = 1; len<=n; len++) { //枚举长度 for(int j = 1; j+len<=n+1; j++) { //枚举起点,ends<=n int ends = j+len - 1; for(int i = j; i<ends; i++) { //枚举分割点,更新小区间最优解 dp[j][ends] = min(dp[j][ends],dp[j][i]+dp[i+1][ends]+something); } } } } int zuichangshangshengzixvlie() { for(int i=2; i<=n+1; i++) { int num=0; for(int j=i-1; j>=1; j--) if(a[i]>a[j]) num=max(num,dp[j]); dp[i]=num+1; } } int zuichanggonggongzixvlie() { char s[MAX],t[MAX]; scanf("%s%s",s,t); int x=strlen(s),y=strlen(t); for(i=0; i<x; i++) { for(j=0; j<y; j++) { if(s[i]==t[j]) dp[i][j]=dp[i-1][j-1]+1; else dp[i][j]=max(dp[i][j-1],dp[i-1][j]); } printf("%d\n",dp[i][j]); } } int zuichanggonggongshangshengzixvlie() { for (int i=1; i<=n; ++i) { int val=0;//val是决策集合S(i,j)中f[i-1][k]的最大值 for(int j=1; j<=m; ++j) { //原来的k循环+判断+状态转移 if (a[i]==b[j]) f[i][j]=val+1; else f[i][j]=f[i-1][j]; if (b[j]<a[i]) val=max(val,f[i-1][j]); //j即将增大为j+1,检查j能否进入新的决策集合 } } } int levenshtien() { char a[N], b[N]; int dp[N][N]; int main() { scanf("%s%s", a, b); int aLen = strlen(a); int bLen = strlen(b); //极端情况 for (int i = 1; i <= aLen; i++) //以i+1来考虑第i个字符的情况 dp[i][0] = i; for (int j = 1; j <= bLen; j++) //以j+1来考虑第j个字符的情况 dp[j][0] = j; for (int i = 1; i <= aLen; i++) { //以i+1来考虑第i个字符的情况 for (int j = 1; j <= bLen; j++) { //以j+1来考虑第j个字符的情况 if (a[i - 1] == b[j - 1]) //相同时距离不变 dp[i][j] = dp[i - 1][j - 1]; else //不同时取三个位置的最小值再+1 dp[i][j] = min(dp[i - 1][j - 1],min(dp[i - 1][j], dp[i][j - 1])) + 1; } } printf("%d\n", dp[aLen][bLen]); return 0; } } int zuidaquanyizhengfangxing() { int ans=0; for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { if(a[i][j]==0) { dp[i][j]=0; } else { dp[i][j]=min(min(dp[i-1][j-1],dp[i-1][j]),dp[i][j-1])+1; } ans=max(ans,dp[i][j]); } } printf("%d\n",ans); } int zuidalianxvziduanhe() { const int inf = 0x7fffffff; int num[101]; int N; cin >> N; for(int i=0; i<N; i++) cin >> num[i]; int ans = -inf; for(int i=0; i<N; i++) ans = max(ans,num[i]); if(ans <= 0) cout << ans << endl; else { int sum =0; for(int i=0; i<N; i++) { if(sum + num[i] < 0) sum = 0; else sum += num[i]; ans = max(ans,sum); } cout << ans << endl; } }
ps:未学完内容在锦集里,别忘了!

浙公网安备 33010602011771号