• 题解 P6454 麻将 加强版


    题目传送门

    题目大意

    不想写了,直接看题面吧。

    思路

    被这个题搞自闭了,因为读错题目想一个非常恶心的东西想了一场考试,然后就删代码,然后就被骂了。哎。

    需要注意的是:我们只能选一次雀头

    于是,不难看出一个 (Theta(n^3)) 的做法,可以枚举听哪张牌,选哪个雀头,然后我们判断的时候显然我们应该多选刻子,选不下去的时候就从后面的值选出连子,实际操作中直接减就行了。也可以看出来,从后往前贪心也是可以的。

    来看 (Theta(n^2)) 做法。不难发现每次听牌的时候贪心前面一部分都是不变的,如果从后往前贪心也是一样。因为我们如果听牌 (a),那么只有后面的牌会受到影响。如果我们假设分别贪到 (l,r) 就不可以再继续贪了,那么我们的雀头一定在 ([r-1,l]) 中(可以看出,在合法情况下 (r<l))。于是,我们可以考虑 dp,我们设 (f_{i,0/1}) 表示从前往后贪心贪到第 (i) 个位置,第 (i+1/i+2) 需要减去的值是多少,同理,我们可以设 (g_{i,0/1}) 表示从后往前的贪心。考虑一个点是否可以被听,可以发现如果设 (x=a_{i}-f_{i-1,0}-g_{i+2,1},y=a_{i+1}),那么当 (x,yge 0) 并且 (x,y) 中任一为 (2) 另一个为 (0)(i-1) 就是可听的。

    所以,时间复杂度就降到了 (Theta(n^2))

    ( exttt{Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define MAXN 5005
    
    template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;}
    template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
    template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    template <typename T> void Mx (T &a,T b){a = max (a,b);}
    template <typename T> void Mi (T &a,T b){a = min (a,b);}
    
    int n,k,a[MAXN],b[MAXN],dp1[MAXN][2],dp2[MAXN][2];
    
    bool check (){
    	for (Int i = 1;i <= n;++ i) b[i] = a[i];
    	int posl = n - 1,posr = 2;//我无论如何怎么选雀头都必须对这两个点产生影响 
    	for (Int i = 1;i <= n - 2;++ i){
    		b[i] -= dp1[i - 1][0];
    		if (b[i] < 0){
    			posl = i;
    			break;
    		}b[i] %= 3;
    		dp1[i][0] = dp1[i - 1][1] + b[i],dp1[i][1] = b[i];
    	}
    	for (Int i = 1;i <= n;++ i) b[i] = a[i];
    	for (Int i = n;i >= 3;-- i){
    		b[i] -= dp2[i + 1][0];
    		if (b[i] < 0){
    			posr = i;
    			break;
    		}b[i] %= 3;
    		dp2[i][0] = dp2[i + 1][1] + b[i],dp2[i][1] = b[i];
    	}
    //	cout << posl << " " << posr << endl;
    	for (Int i = posr - 1;i <= posl;++ i){
    		int x = a[i] - dp1[i - 1][0] - dp2[i + 2][1],y = a[i + 1] - dp1[i - 1][1] - dp2[i + 2][0];
    		if (x >= 0 && y >= 0) 
    			if ((x % 3 == 0 && y % 3 == 2) || (x % 3 == 2 && y % 3 == 0)) 
    				return 1;
    	}
    	for (Int i = 1;i <= n;++ i) if (a[i] & 1) return 0;
    	return 1;
    }
    
    signed main(){
    	read (n,k);
    	for (Int i = 1,val;i <= k;++ i) read (val),++ a[val];
    	vector <int> ans;
    	for (Int i = 1;i <= n;++ i){
    		++ a[i];
    		if (check ()) ans.push_back (i);
    		-- a[i];
    	}
    	write (ans.size()),putchar ('
    ');
    	for (Int v : ans) write (v),putchar (' ');
    	return 0;
    }
    
  • 相关阅读:
    *关于如何获取指定表的指定字段的数据类型的方法
    *检查表是否存在
    *用Sql添加删除字段,判断字段是否存在的方法
    *MSSQL三个关键系统表
    *系统表的应用
    VC++ ADO编程入门简介
    int i=0; i=i++ System.out.Println(i)
    Microsoft Visual C++ 6.0 关联源代码
    VC ADO接口详解
    程序员每年该做的事
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/13855246.html
Copyright © 2020-2023  润新知