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;
}
标签:const,NOIP,int,text,long,ABC278F,using,赛前,define
From: https://www.cnblogs.com/qinchenhao/p/16909305.html