心路历程是这样纸的:
翻到一道bzoj的题,泡泡堂BNB,恩,题意很简单,就像田忌赛马那样dp一下就好了,可是dp是n^2的,这里的数据变成了10W,怎么办?
瞬间懵逼~懵逼~~
翻了一下田忌赛马那道题,考虑了一下dp,看能不能优化:
这样dp的:
现将两个人的马从大到小排序
定义f[i][j]表示对于齐王的前i强的马,用了前j强的马和i-j弱的马获得的最大利益。
f[i][j]=max(f[i-1][j-1]+g[i][j],f[i-1][j]+g[i][n-(i-j)+1]); g[i][j]表示齐王的第i强和田忌的第j强相比,田忌的获利。
还是一个n^2的dp,n(n-1)/2,对于10W是跑不下的呀!
然后懵逼了,猜测也许会用贪心,but不会贪
然后求助网上的题解- - -- - - - -- - - -- - -
网上是这么搞的:
也是先排序,然后考虑田忌的当前最强的马和齐王最强的马相比:
如果田忌马强,直接比,因为这匹马一定会赢,不如赢掉能赢掉的最强的。
如果弱,用田忌最弱的,因为反正会输,不如用最差的消耗掉最强的。
如果平:
1.田忌最弱的比齐王最弱的强,比赛过去,因为齐王的那匹弱马一定会输,不如用最差的赢掉。
2.其他情况,用田忌最弱的和期望最强的比,要么输要么平。
(为什么这样做是最优的?考虑3匹马,如果发生了这种情况,这么做一定不会最差)
然后就代码了。
然后类比田忌赛马的贪心,bzoj1034也可以做了:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
const int maxn=100000+20;
/*
按实力值从大到小排序
感觉有点像田忌赛马,在最好情况的时候,定义f[i][j]表示选了前
*/
int n;
int mi[maxn],dui[maxn];
bool cmp(int x,int y)
{
return x>y;
}
int work(int *ti,int *qi)
{
int ans=0;
int h1=1,t1=n,h2=1,t2=n;
for(int i=1;i<=n;i++)
{
if(ti[h1]>qi[h2])
{
ans+=2;
h1++;
h2++;
}
else if(ti[h1]<qi[h2])
{
t1--;
h2++;
}
else
{
if(ti[t1]>qi[t2])
{
ans+=2;
t1--;
t2--;
}
else
{
if(ti[t1]==qi[h2])ans++;
t1--;
h2++;
}
}
}
return ans;
}
int best()
{
return work(mi,dui);
}
int worst()
{
return 2*n-work(dui,mi);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&mi[i]);
for(int i=1;i<=n;i++)scanf("%d",&dui[i]);
sort(mi+1,mi+n+1,cmp);
sort(dui+1,dui+n+1,cmp);
printf("%d %d\n",best(),worst());
return 0;
}