zoukankan      html  css  js  c++  java
  • 博弈(game)

    前言

    这题要是放NOIP说不定就让我退役了

    题目

    讲解

    为了方便,我们令最终剩下的数为(s)

    part1 35pts

    首先我们用记忆化搜索轻松写出(O(N^2))的算法

    定义(dp[w][i][j])表示此时左端点为(i),右端点为(j),此时是(w(0/1))人取的时候的最优取值

    代码就不给出了

    part2 45pts

    我们考虑(K=0)小B没有女朋友的时候答案应该如何快速求出

    考虑分奇偶讨论

    1.如果(N)为奇数

    (s)一定出自中间三个数,令他们依次为(t_1,t_2,t_3)

    考虑如果答案不是出自中间三个数

    • 小A想取左边或者右边的数,这样一定对小B不优,小B就会在对面取数,中间的数始终不变,答案一定在中间三个数中产生
    • 小B想取左边或者右边的数,这样一定对小A不优,从第三次取数开始,类似的,小A也会在小B的对边取数,这样答案也一定在中间三个数中产生

    当最后剩下(t_1,t_2,t_3)三个数的时候,一定是小A取数,如果(t_2)最小,那么小B一定可以使它被取到

    如果(t_2)不是最小,小A自己不可能取走(t_1,t_3)中一个最大的数,他一定会取走最小的数,剩下一个次大值和最

    大值,而小B一定会取走最大值,那么(s)即为次大值

    2.如果(N)为偶数

    类似的,(s)一定出自中间的(t_1,t_2)两个数

    此时轮到小A取数,取走最小值,剩下最大值

    于是我们就可以(O(1))求出(K=0)时的答案了

    我称这个结论为中心论

    part3 65pts

    笔者在考场上就只码出了这个部分分,结果艹过了70pts...

    明显part2推论还可以拓展为求剩下区间为([l,r])的时候,小A先取数时的(s)

    对应代码即为:

    int Get(int l,int r)
    {
    	if(l == r) return a[l];
    	if((r-l+1) & 1) 
    	{
    		int t1 = (l+r-1)/2,t2 = (l+r-1)/2+1,t3 = (l+r-1)/2+2;
    		t[1] = a[t1]; t[2] = a[t2]; t[3] = a[t3];
    		if(t[2] < t[1] && t[2] < t[3]) return t[2];
    		else {sort(t+1,t+3+1);return t[2];}
    	}
    	else 
    	{
    		int t1 = (l+r-1)/2,t2 = (l+r-1)/2+1;
    		return Max(a[t1],a[t2]);
    	}
    }
    

    当然这部分的代码也可以替换part1的记忆化搜索,毕竟这是(O(1))的查询,对于每个(K)求答案时可以做到(O(N)),共(O(N^2))

    我们对于每个(K)可以(O(N))枚举提前取数区间求出

    (O(N^2)),如果(Kge 0),即为(O(N))

    part4 100pts

    现在我们考虑拿走边上的数会造成什么影响

    由于我们分奇偶讨论,拿走奇数个的时候会对奇偶性造成影响,而奇偶性不同的时候求(s)的方法不同,不能合起来讨论,所以我们试图分析拿走偶数个的时候会发生什么

    考虑拿走两个数

    如果一边拿走一个数,中心不会发生改变!所以(s)并不会改变!

    如果单边拿走两个数,中心发生偏移,但是偏移不多,我们可以用两次(Get)操作求出这左右两种取数后的(s),与前一种取数方案的(s)取一个最大值,即为当前(K)的答案

    于是可以(O(N))递推

    但是注意,当(K=N-1)的时候,此时我们的中心论已经不成立了,因为所有数都可能成为答案,需要特判

    代码

    int Get(int l,int r)
    {
    	if(l == r) return a[l];
    	if((r-l+1) & 1) 
    	{
    		int t1 = (l+r-1)/2,t2 = (l+r-1)/2+1,t3 = (l+r-1)/2+2;
    		t[1] = a[t1]; t[2] = a[t2]; t[3] = a[t3];
    		if(t[2] < t[1] && t[2] < t[3]) return t[2];
    		else {sort(t+1,t+3+1);return t[2];}
    	}
    	else 
    	{
    		int t1 = (l+r-1)/2,t2 = (l+r-1)/2+1;
    		return Max(a[t1],a[t2]);
    	}
    }
    int ans[MAXN];
    void solve_all()
    {
    	ans[0] = Get(1,n);
    	ans[1] = Max(Get(1,n-1),Get(2,n));
        //初始化递推边界
    	for(int i = 2;i < n;++ i) ans[i] = Max(ans[i-2],Max(Get(1,n-i),Get(1+i,n)));
        //O(N)递推,从i-2的状态推过来
    	for(int i = 1;i <= n;++ i) ans[n-1] = Max(ans[n-1],a[i]);
        //特判,因为 "中心论" 不适用了
    }
    void solve()
    {
    	if(k >= 0)
    	{
    		int len = n-k,Ans = 0;
    		for(int i = 1;i+len-1 <= n;++ i)
    			Ans = Max(Ans,Get(i,i+len-1));
    		Put(Ans);
            //当然这并没有必要,只是常数优化
    	}
    	else
    	{
    		solve_all();
    		for(int i = 0;i < n;++ i)
    			Put(ans[i],' ');
    	}
    }
    
    int main()
    {
    //	freopen("game3.in","r",stdin);
    //	freopen("mine.out","w",stdout);
    	n = Read(); k = Read();
    	for(int i = 1;i <= n;++ i) a[i] = Read();
    	solve();
    	return 0;
    }
    

    个人代码有些冗长,如果你不想看的话可以康康下面的std

    #include<bits/stdc++.h>
    using namespace std;
    const int N=200005;
    int n,k,a[N],ans[N];
    int gt(int l,int r)
    {
    	int mid=(l+r)/2,len=r-l+1;
    	if(len&1)return max(min(a[mid-1],a[mid]),min(a[mid],a[mid+1]));
    	return max(a[mid],a[mid+1]); 
    }
    int main()
    {
    //	freopen("game.in", "r", stdin);
    //	freopen("game.out", "w", stdout);
    	scanf("%d%d",&n,&k);
    	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    	ans[0]=gt(1,n);ans[1]=max(gt(1,n-1),gt(2,n));
    	for(int i=2;i<n;i++)ans[i]=max(ans[i-2],max(gt(1,n-i),gt(i+1,n)));
    	for(int i=1;i<=n;i++)ans[n-1]=max(ans[n-1],a[i]);
    	if(k>=0)printf("%d
    ",ans[k]);
    	else for(int i=0;i<n;i++)printf("%d ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    LeetCode Subarrays with K Different Integers
    LeetCode Repeated DNA Sequences
    为什么要使用静态方法
    String,StringBuilder,StringBuffer
    汉诺塔递归算法
    设计模式之代理模式
    设计模式之单例设计模式
    设计模式之工厂方法和抽象工厂
    设计模式之模板方法
    并发技巧清单(1)
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/13739639.html
Copyright © 2011-2022 走看看