「NOIP赛前冲刺」ABC278F

Solution

简单状态压缩,考虑设 \(f_{S,i}\) 表示状态为 \(S\) 并且当前要求一个开头为 \(s_i\) 的结尾字符的单词,\(\text{First}\) 如果能赢为 \(0\),否则为 \(1\)

那么很明显有

\[f_{S|2^{j-1},j}=[f_{S,i}=0]\times[end_i=begin_j] \]

枚举 \(S,i,j\) 即可,时间复杂度为 \(O(2^nn^2)\) ,注意最后如果存在 \(f_{2^{i-1},i}=1\) 代表 \(\text{First}\) 赢,否则代表 \(\text{Second}\) 赢。

Code

#include<bits/stdc++.h>
using namespace std;
using db=double;
using ll=long long;
using vi=vector<int>;
using pii=pair<int,int>;
using ull=unsigned long long;
#define ft first
#define sd second
#define gc getchar
#define pb push_back
#define emp emplace_back
#define mp make_pair
#define sz(a) (int)a.size()
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define ROF(i,a,b) for(int i=a;i>=b;i--)
#define lowbit(x) ((x)&(-x))
#define int long long
const int N=1e5+7;
const int mod=1e9+7;
const int INF=(1ll<<60);
const int inf=1e9;
const int K=5e5+1;
void read(int &x)
{
	char ch=getchar();
	int r=0,w=1;
	while(!isdigit(ch))w=ch=='-'?-1:1,ch=getchar();
	while(isdigit(ch))r=(r<<3)+(r<<1)+(ch^48),ch=getchar();
	x=r*w;
}
void write(int x) {
	char ch[20];
	int len = 0;
	if (x < 0)putchar('-'), x = -x;
	while (x) {
		ch[len++] = (x % 10) ^ 48;
		x /= 10;
	}
	if(len==0)printf("0");
	while (len--)putchar(ch[len]);
	puts("");
}
char s[N];
int x[N],y[N];
bool f[N][30];
signed main()
{
	int n;
	read(n);
	FOR(i,1,n)scanf("%s",s+1),
	x[i]=s[1]-'a'+1,y[i]=s[strlen(s+1)]-'a'+1;
	ROF(S,(1ll<<n)-1,1)
	{
        FOR(i,1,n)
            if(S>>(i-1)&1) 
                FOR(j,1,n)                
                {
                    if(S>>(j-1)&1)continue;
                    int t=S|1ll<<(j-1);
                    if(y[i]==x[j]&&f[t][j]==0) 
                    	f[S][i]=1;
                }
    }
    FOR(i,1,n)
    {
        if(!f[1ll<<(i-1)][i]) 
        {
        	puts("First");
        	return 0;
        }
    }
    puts("Second");
    return 0;
}
posted @ 2022-11-20 19:36  xiaoPanda  阅读(87)  评论(0)    收藏  举报