「雜題亂刷」CF1987D

wangmarui發表於2024-07-01

題目連結

CF1987D World is Mine

提示

  1. Alice 的策略是固定的。

  2. 考慮用動態規劃解決問題。

解題思路

我們發現,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  2

hack:
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;
}