CF573D Bear and Cavalry
2021/7/23 23:25:08
本文主要是介绍CF573D Bear and Cavalry,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
一、题目
点此看题
二、解法
首先根据农民伯伯都会的排序不等式(因为他们知道把最好的菜种进最好的地里),贪心策略是把人和马都按照权值大小排序,然后对应位相乘求和就行了,不难证明这是最优的匹配方案。
但是因为本题有第 \(i\) 个人不能和第 \(i\) 匹马配对的限制,所以说不一定取得到最优方案。这时候我想反悔贪心但是贪不出来(可能不适用,因为本题是最优解取不到的情况),但是考虑这个限制不是很多,可以往结论方向想。
感觉上和每个人匹配的马和它相差的位置不会太远,可以往匹配距离较小这个方向想。结论:不存在 \((i,i\pm 3)\) 这样的匹配,可以考虑反证\(+\)调整法,先假设会出现这样的情况,设 \(i\) 的禁止匹配位置为 \(ban[i]\):
因为要完美匹配,所以至少会有三条红线和黑线相交。利用调整法不难证明如果两条线相交那么交换这两个匹配会得到更优的解,我们要考虑的是这样交换是否合法。注意到红线终点至多有一个是 \(ban[i]\),红线起点至多有一个的 \(ban=i+3\),就算是这样剩下的那一个就会合法,可以和它调整,那么这不是最优解,所以不存在 \((i,i\pm3)\) 的匹配。
然后考虑用 \(dp\) 解决问题,推论:如果只考虑前 \(i\) 个位置的匹配,那么只有可能 \([i-k,i]\ \ \ 0\leq k\leq 2\) 内部匹配然后得到子问题。设 \(f_i\) 为前 \(i\) 个位置匹配的最优解,那么转移:
因为本题带修,所以把转移写成矩阵然后跑动态 \(dp\) 即可,时间复杂度 \(O(n\log n\cdot 3^3)\)
三、总结
转化到一定程度了可以猜一猜结论,可以靠一点感觉。
当限制条件不多时(比如本题只限制了某人不能匹配某马),那么可以强行摆脱限制(比如本题证明是跨越三个点那么怎么限制都阻止不了你调整),调整法是很重要的思维方式。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define int long long const int M = 30005; const int inf = 0x3f3f3f3f3f3f3f3f; int read() { int x=0,f=1;char c; while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;} while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();} return x*f; } int n,m,a[M],b[M],p1[M],p2[M],ban[M]; struct node { int x,id; bool operator < (const node &b) const { return x<b.x; } }s[M],t[M]; struct mat { int a[3][3]; mat() {memset(a,-0x3f,sizeof a);} mat operator * (const mat &b) const { mat r; for(int i=0;i<3;i++) for(int j=0;j<3;j++) for(int k=0;k<3;k++) r.a[i][k]=max(r.a[i][k],a[i][j]+b.a[j][k]); return r; } }tr[4*M]; mat con(int x) { mat r; r.a[1][0]=r.a[2][1]=0; r.a[0][0]=(ban[x]!=x)?a[x]*b[x]:-inf; if(x<=1) return r; r.a[0][1]=(ban[x]!=x-1 && ban[x-1]!=x) ?a[x-1]*b[x]+a[x]*b[x-1]:-inf; if(x<=2) return r; int c1=(ban[x]!=x-2 && ban[x-1]!=x && ban[x-2]!=x-1) ?a[x]*b[x-2]+a[x-1]*b[x]+a[x-2]*b[x-1]:-inf; int c2=(ban[x]!=x-1 && ban[x-1]!=x-2 && ban[x-2]!=x) ?a[x]*b[x-1]+a[x-1]*b[x-2]+a[x-2]*b[x]:-inf; r.a[0][2]=max(c1,c2); return r; } void ins(int i,int l,int r,int id) { if(l==r) { tr[i]=con(l); return ; } int mid=(l+r)>>1; if(mid>=id) ins(i<<1,l,mid,id); else ins(i<<1|1,mid+1,r,id); tr[i]=tr[i<<1|1]*tr[i<<1];//attention } signed main() { n=read();m=read(); for(int i=1;i<=n;i++) s[i].x=read(),s[i].id=i; for(int i=1;i<=n;i++) t[i].x=read(),t[i].id=i; sort(s+1,s+1+n); sort(t+1,t+1+n); for(int i=1;i<=n;i++) { a[i]=s[i].x;b[i]=t[i].x; p1[s[i].id]=i,p2[t[i].id]=i; } for(int i=1;i<=n;i++) ban[p1[i]]=p2[i]; for(int i=1;i<=n;i++) ins(1,1,n,i); while(m--) { int x=p1[read()],y=p1[read()]; swap(ban[x],ban[y]); for(int i=max(1ll,x-2);i<=min(n,x+2);i++) ins(1,1,n,i); for(int i=max(1ll,y-2);i<=min(n,y+2);i++) ins(1,1,n,i); printf("%lld\n",tr[1].a[0][0]); } }
这篇关于CF573D Bear and Cavalry的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-22怎么通过控制台去看我的页面渲染的内容在哪个文件中呢-icode9专业技术文章分享
- 2024-12-22el-tabs 组件只被引用了一次,但有时会渲染两次是什么原因?-icode9专业技术文章分享
- 2024-12-22wordpress有哪些好的安全插件?-icode9专业技术文章分享
- 2024-12-22wordpress如何查看系统有哪些cron任务?-icode9专业技术文章分享
- 2024-12-21Svg Sprite Icon教程:轻松入门与应用指南
- 2024-12-20Excel数据导出实战:新手必学的简单教程
- 2024-12-20RBAC的权限实战:新手入门教程
- 2024-12-20Svg Sprite Icon实战:从入门到上手的全面指南
- 2024-12-20LCD1602显示模块详解
- 2024-12-20利用Gemini构建处理各种PDF文档的Document AI管道