题目
题目描述
神树大人造了一个长为
n
n
n 的
0
-
1
0\text{-}1
0-1 序列,并邀请无所事事的神
J
J
J 来和他博弈。
每一轮里,若这个序列的第一项是 0 0 0 ,那么神树大人可以选择让它不变或者变成 1 1 1 ;若这个序列的第一项是 1 1 1 ,那么神 J J J 可以选择让它不变或者变成 0 0 0 。接着对这个序列进行旋转操作:即将第 1 1 1 项放到第 n n n 项的后面,其他项依次替补。如果这个序列变为全 0 0 0 ,那么神 J J J 胜利;如果存在一种方法让神 J J J 永远不能胜利,那么神树大人胜利。
一个可能的游戏如下:
- 初始状态 0 , 1 0,1 0,1 。
- 第一项是 0 0 0 ,神树大人让他变成 1 1 1 。序列变为: 1 , 1 1,1 1,1 。
- 第一项是 1 1 1 ,神 J J J 让他变成 0 0 0 。序列变为: 1 , 0 1,0 1,0 。
- 第一项是 1 1 1 ,神 J J J 让他变成 0 0 0 。序列变为: 0 , 0 0,0 0,0 。
神 J J J 胜利。
现在,你作为神 J J J 的信徒,打算计算有多少种长为 n n n 的 01 01 01 序列使得神 J J J 胜利。
输入格式
第一行输入一个
n
n
n 。
输出格式
输出答案对
998244353
998244353
998244353 取模。
数据范围与约定
对于
30
%
30\%
30% 的数据,
n
≤
5
n\leq 5
n≤5 。
对于
60
%
60\%
60% 的数据,
n
≤
20
n\leq 20
n≤20 。
对于
100
%
100\%
100% 的数据,
n
≤
1
0
5
n\leq 10^5
n≤105 。
思路
我一开始打了个爆搜。用状态压缩表示目前的序列,遵循如下规律:神 J J J 可以操作时,只要有一个后继状态是神 J J J 必胜,那么当前状态神 J J J 必胜;神树可以操作时,仅当两个后继都是神 J J J 必胜才是必胜状态。
用一个类似拓扑方法,从必胜态全 0 0 0 开始。话说打代码的时候突然意识到,无论是谁操作,后继状态是一样的 😂
const int MaxN = 20;
vector<int> g[1<<MaxN]; int n;
void buildEdge(){
/* 所有可能的下个状态 */
for(int i=0; i<(1<<n); ++i){
int j = (i<<1)&((1<<n)-1);
g[j].push_back(i);
g[j|1].push_back(i);
}
}
vector<int> tmp; int ans, degree[1<<MaxN];
void solve(){
for(int i=0; i<(1<<n); ++i)
for(int j=0,len=g[i].size(); j<len; ++j)
degree[g[i][j]] ++;
tmp.push_back(0); degree[0] = -1;
while(not tmp.empty()){
int t = tmp.back();
tmp.pop_back(); ++ ans;
for(int i=0,len=g[t].size(); i<len; ++i){
if(g[t][i] >= (1<<n>>1) and degree[g[t][i]] > 0){
tmp.push_back(g[t][i]);
degree[g[t][i]] = -1;
}
if(not (-- degree[g[t][i]])){
tmp.push_back(g[t][i]);
degree[g[t][i]] = -1;
}
}
}
printf("%d\n",ans);
}
然后发现,在 n ≤ 20 n\le 20 n≤20 时,答案等于 2 n 2^n 2n 。
但是能够证明对于 n ≤ 1 0 5 n\le 10^5 n≤105 也成立吗?
有句老话说的好:OI的结论都要证明,和数竞有什么区别。
证明在此。很有意思。
代码
略。