题目链接
CF1987D World is Mine
提示
-
Alice 的策略是固定的。
-
考虑用动态规划解决问题。
解题思路
我们发现,Alice 的最优策略一定是每次取当前能取的美味值最小的蛋糕,而 Bob 的策略难以使用贪心维护。
于是我们考虑用动态规划来考虑 Bob 的策略。
我们发现,Bob 想让让 Alice 吃不到某种蛋糕,当且仅当 Bob 把这个种类的所有蛋糕都拿走了。因此我们需要开个桶来记录每个种类的蛋糕所出现的数量。
于是我们就可以将 Bob 蛋糕的个数加 \(1\) 化为 Bob 拿蛋糕的代价(加上一是因为 Alice 是先手),而 \(1\) 就是 Bob 获得的收益,于是我们就可以直接 dp,\(dp_{i,j}\) 表示 Bob 考虑到前 \(i\) 个蛋糕,花的代价为 \(j\) 时可以拿掉的最大蛋糕种类数是多少。
最终答案即为直接用原本的蛋糕种类数减去 Bob 最大拿掉的蛋糕种类数。
时间复杂度 \(O(n^2)\)。
参考代码
点击查看代码
/*
Tips:
你数组开小了吗?
你MLE了吗?
你觉得是贪心,是不是该想想dp?
一个小时没调出来,是不是该考虑换题?
打 cf 不要用 umap!!!记住,rating 是身外之物。该冲正解时冲正解!Problem:算法:思路:*/
#include<bits/stdc++.h>
using namespace std;
//#define map unordered_map
#define re register
#define ll long long
#define forl(i,a,b) for(re ll i=a;i<=b;i++)
#define forr(i,a,b) for(re ll i=a;i>=b;i--)
#define forll(i,a,b,c) for(re ll i=a;i<=b;i+=c)
#define forrr(i,a,b,c) for(re ll i=a;i>=b;i-=c)
#define lc(x) x<<1
#define rc(x) x<<1|1
#define mid ((l+r)>>1)
#define cin(x) scanf("%lld",&x)
#define cout(x) printf("%lld",x)
#define lowbit(x) (x&-x)
#define pb push_back
#define pf push_front
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define endl '\n'
#define QwQ return 0;
#define db long double
#define ull unsigned long long
#define lcm(x,y) x/__gcd(x,y)*y
#define Sum(x,y) 1ll*(x+y)*(y-x+1)/2
#define aty cout<<"Yes\n";
#define atn cout<<"No\n";
#define cfy cout<<"YES\n";
#define cfn cout<<"NO\n";
#define xxy cout<<"yes\n";
#define xxn cout<<"no\n";
#define printcf(x) x?cout<<"YES\n":cout<<"NO\n";
#define printat(x) x?cout<<"Yes\n":cout<<"No\n";
#define printxx(x) x?cout<<"yes\n":cout<<"no\n";
ll t;
ll n;
ll a[5010];
ll b[5010];
ll c[5010],d[5010];
ll pd,ans;
ll lst,k;
ll dp[5010][5010];
/*
A选此时最小的B选此时值最大且数量最少的 dp!!!!你发现每个东西有你需要拿的时间还有什么时候之前你要拿掉dp[i][j]表示第i个蛋糕,使用了j个时间的干掉的最大蛋糕数
*/
/*
1 2 3 5 6 9
2 3 3 2 5 2hack:
10
4
1 4 2 3
3
1 1 1
5
1 4 2 3 4
4
3 4 1 4
1
1
8
4 3 2 5 6 8 3 4
7
6 1 1 3 5 3 1
11
6 11 6 8 7 5 3 11 2 3 5
17
2 6 5 3 9 1 6 2 5 6 3 2 3 9 6 1 6
11
1 2 2 2 3 3 3 4 4 4 5
*/
void solve()
{pd=1,k=0;cin>>n;forl(i,1,n)cin>>a[i],b[a[i]]++;forl(i,1,5000)if(b[i])k++,c[k]=k,d[k]=b[i]+1;forl(i,1,k){forr(j,i,0){dp[i][j]=max(dp[i][j],dp[i-1][j]);if(j+d[i]<=i)dp[i][j+d[i]]=max(dp[i][j+d[i]],dp[i][j]+1);}}ll ma=0;forl(i,1,k){forl(j,0,i)/* cout<<"["<<i<<','<<j<<']'<<dp[i][j]<<' ',*/ma=max(ma,dp[i][j]),dp[i][j]=0;// cout<<endl;}cout<<k-ma<<endl; forl(i,1,5000)a[i]=b[i]=c[i]=d[i]=0;
/* while(1){if(pd){forl(i,1,5000){if(b[i]){b[i]--;ans++;lst=i;break; }if(i==5000){cout<<ans<<endl;return ;}}pd^=1;}else{ll mi=1e18,id=0,sum=0;forl(i,lst+1,5000){if(b[i])c[]}pd^=1;}}*/
}
int main()
{IOS;t=1;cin>>t;while(t--)solve();/******************//*while(L<q[i].l) *//* del(a[L++]);*//*while(L>q[i].l) *//* add(a[--L]);*//*while(R<q[i].r) *//* add(a[++R]);*//*while(R>q[i].r) *//* del(a[R--]);*//******************/QwQ;
}