bzoj1237 [SCOI2008]配对 贪心结论+插数dp

来源:互联网 发布:淘宝电工工具袋 编辑:程序博客网 时间:2024/04/30 16:52

如果没有相同的数不能配的情况下,就直接排序后对位配就可以了,由单调性很好证明

然后如果有相同不能配的情况,那配对的数字在排完序的数列里一定不会跨度太大,因为离得越远意味着差值越大

然后就需要定量考虑到底要跨多少

只有相同的才会产生跨度,如果相同的有连续2个 就是交叉相连,如果3个,就有两种情况 ,如果4个,显然两个X更优

以后的就用X逼近,剩下3个就连成キ的两种情况就可以了


码:

#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>using namespace std;long long n,i,j,f[99999][5],a[99999],b[99999];int main(){scanf("%lld",&n);for(i=1;i<=n;i++){scanf("%lld%lld",&a[i+2],&b[i+2]);}sort(a+3,a+3+n);sort(b+3,b+3+n);f[0][0]=f[1][0]=1000000000000000000;f[2][0]=0;for(i=3;i<=n+2;i++)//0:全都配过了 1:最后一对没配 2: 最后两对没配 {f[i][0]=min(min(f[i-3][0]+abs(a[i]-b[i-1])+abs(a[i-1]-b[i-2])+abs(a[i-2]-b[i]),f[i-3][0]+abs(a[i]-b[i-2])+abs(a[i-1]-b[i])+abs(a[i-2]-b[i-1])),f[i-2][0]+abs(a[i]-b[i-1])+abs(b[i]-a[i-1]));if(a[i]!=b[i]){f[i][0]=min(f[i-1][0]+abs(a[i]-b[i]),f[i][0]);}}if(f[n+2][0]==1000000000000000000)printf("-1");elseprintf("%lld",f[n+2][0]);}