【题解】[ABC304F] Shift Table(容斥)
Sunflower_ac · · 题解
【题解】[ABC304F] Shift Table
题目链接
[ABC304F] Shift Table
题意概述
Takahashi 和 Aoki 将在接下来的
Takahashi 这 # 则表示他在第 . 表示他在第
Aoki 的出勤情况如下:
- 首先选择一个
N 的正因数M ,其中M\ne N ; - 接下来安排
1 到M 天的出勤情况; - 最后安排
M+1 到N 天的出勤情况,使得对于任意i(1\le i \le M) ,第kM+i 天的出勤情况与第i 天一致。
注意:不同的
求 Aoki 可能的出勤情况安排数量,使得 Takahashi 和 Aoki 至少在每一天都有一人工作。
答案对
数据范围
-
1\le N \le 10^5
题目分析
首先我们发现,
那么很容易想到去枚举因子 ,考虑
对于每个因子
由于必须保证两人至少在每一天都有一人工作,所以若第
基于此,我们可以定义一个 .,则将
那么对于
所以对于每个因子
观察样例可以发现,对于所有的
我们考虑什么样的
所以我们可以对于每一个因子
最后,所有的因子贡献之和即为答案。
时间复杂度
代码实现
//F
//The Way to The Terminal Station…
#include<cstdio>
#include<iostream>
#include<vector>
#include<set>
#define int long long
using namespace std;
const int maxn=1e5+10;
const int mod=998244353;
set<int>p,q;
int vis[maxn],sum[maxn];//vis[i] 表示的是每一份的第 i 天是否必须出勤,sum[i] 表示的是因子 i 的贡献。
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
signed main()
{
int n=read();
string s;
cin>>s;
s='%'+s;
//预处理出 n 的所有因子
for(int i=1;i<n;i++)
{
if(n%i==0)p.insert(i);
}
//枚举所有的因子,考虑每个因子的贡献。
int ans=0;
for(int v:p)
{
for(int i=1;i<=v;i++)vis[i]=0;
for(int i=1;i<=n;i++)
{
int t=i%v;
if(t==0)t=v;
if(s[i]=='.')vis[t]=1;
}
sum[v]=1;
for(int i=1;i<=v;i++)
{
if(!vis[i])(sum[v]*=2)%=mod;
}
//容斥,计算每个因子单独的贡献。
for(int vv:p)
{
if(vv==v)break;
if(v%vv==0)sum[v]=(sum[v]-sum[vv]+mod)%mod;
}
(ans+=sum[v])%=mod;
}
cout<<ans<<'\n';
return 0;
}