遊戲 - 博弈論 - 結論

題目大意:你有兩個序列{an}{bm}\{a_n\}\{b_m\},以及兩個指針c,dc,d,初始c=d=1c=d=1。有兩個人,每次每個人可以選擇修改c和d中的恰好一個,或者結束遊戲,結果是ac+bda_c+b_d。同一對(c,d)不能被訪問100次。第一個人希望結果儘量小,第二個人希望結果儘量大,問最後結果是多少。
題解:首先等價於每一對(c,d)只能訪問一次。然後二分答案x,看先手能否使得結果不大於x。這樣一開始結果是大於x的,先手必須調整使其小於等於x,然後第二個人再讓結果大於x……將ac+bdxa_c+b_d\le x的(c,d)看做白點,否則黑點,相當與每次每人都要把棋子從當前點移動到顏色不同的沒有被訪問過的點。不能移動者輸。
這是個經典結論,結論是某個白點先手必勝當且僅當其在一個最大匹配上。
因此只需要看刪掉這個點是否最大匹配減小1。轉化一下發現這等價於最大獨立集不變。然後發現如果a和b都從小到大排序,那麼一定存在一個最優解,存在一個分界點,選出來的白點都在分界點左上,黑點都在右下。接着發現枚舉橫座標後,分界點縱座標越大,獨立集增量越小,所以可以二分;接着發現當橫座標變大的時候,最優的縱座標不會變小,因此可以在線性時間內完成判定。最後如何判定扣去一個點的最大獨立集ans2和原來最大獨立集ans1是否一樣,這個注意到如果ans2的分界點在扣去的點的左上,那麼ans1一定大於ans2。因此也就是想知道是否存在一個分界點,取到最大獨立集,並且右下方沒有扣去的點即可。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
	int x,ch;while((ch=gc)<'0'||ch>'9');
	x=ch^'0';while((ch=gc)>='0'&&ch<='9')
		x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const int N=100010;
int a[N],b[N],R[N],U[N];
inline int check(int x,int n,int m,int p1,int p2)
{
	for(int i=1,j=m;i<=n;R[i++]=j)
		while(j&&a[i]+b[j]>x) j--;R[0]=m,R[n+1]=0;
	rep(i,0,n) rep(j,R[i+1]+1,R[i]) U[j]=i+1;
	lint s=0;rep(i,1,m) s+=n-U[i]+1;lint ans1=s,ans2=s-1;
	for(int i=0,j=0;i<=n;i++)
	{
		s+=min(R[i],j)-(m-max(R[i],j));
		while(j<m&&min(i,U[j+1]-1)>=n-max(U[j+1],i+1)+1)
			s+=min(i,U[j+1]-1)-(n-max(U[j+1],i+1)+1),j++;
		ans1=max(ans1,s),ans2=max(ans2,s-(p1>i&&p2>j));
	}
	return ans1==ans2;
}
int main()
{
	int n=inn(),m=inn();
	rep(i,1,n) a[i]=inn();int v1=a[1];
	rep(i,1,m) b[i]=inn();int v2=b[1];
	sort(a+1,a+n+1),sort(b+1,b+m+1);
	int p1=0;rep(i,1,n) if(a[i]==v1) p1=i;
	int p2=0;rep(i,1,m) if(b[i]==v2) p2=i;
	int L=a[1]+b[1],R=v1+v2-1;
	while(L<=R)
	{
		int mid=(L+R)>>1;
		if(check(mid,n,m,p1,p2)) R=mid-1;
		else L=mid+1;
	}
	return !printf("%d\n",L);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章