22杭电多校11 Find different(环计数问题)

题意:给定一个环,环大小为n,环上每个数取值范围为[0,m-1],能通过旋转或者模m意义下整体加任意数得到的环视为同构体,求不同的方案数。

Solution:
\quad 本题有两个同构体条件。先看模意义下加法,可以转化为差分数组。
\quad 设环上的数为ai,设 b i = a i − a ( i − 1 + m o d ) m o d   m b_i=a_i-a_{(i-1+mod)mod\,m} bi=aia(i1+mod)modm。因为整体是个环,所以有 ∑ b i = 0 \sum{b_i}=0 bi=0(模m意义下)。只考虑模意义下加法同构的话,也就是差分数组要不同的方案数为 m n − 1 m^{n-1} mn1(前n-1个bi任意取)
\quad 现在加上旋转同构体考虑,通过上面的分析,我们现在只要关注差分数组bi旋转同构即可。
\quad 我们用传统的环计数方法来推导(菜鸡博主不会用polyaQAQ)。考虑环的循环节,设 f ( i ) f(i) f(i)表示环上最小循环节为i的方案数(含旋转同构,也就是说旋转同构会算重), g ( i ) g(i) g(i)表示存在环循环节为i的方案数(含旋转同构)。比如说123123在g(6)中算,f(6)中不算,f(3)算。
\quad 设循环节长度为d,则有 n d \frac{n}{d} dn个循环节。设一节的bi数组和为 s ( m o d   m ) s(mod\,m) s(modm),有 s = ∑ i = 1 d b i s=\sum_{i=1}^{d}b_i s=i=1dbi。因为 ∑ b i = 0 ( m o d   m ) \sum{b_i}=0(mod\,m) bi=0(modm),则有 m ∣ s ∗ n d m\mid s*\frac{n}{d} msdn,其中s的范围为[0,m-1]等价于[1,m](模m意义下)。假如符合上述约束的s有k个,则 g ( d ) = m d − 1 ∗ k g(d)=m^{d-1}*k g(d)=md1k
k = ∑ i = 1 m [ m ∣ i ∗ n d ] k=\sum_{i=1}^m[m\mid i*\frac{n}{d}] k=i=1m[midn],提出 g c d ( m , n d ) ,设 p = m g c d ( m , n d ) , 设 q = n d g c d ( m , n d ) gcd(m,\frac{n}{d}),设p = \frac{m}{gcd(m,\frac{n}{d})},设q=\frac{\frac{n}{d}}{gcd(m,\frac{n}{d})} gcd(m,dn),设p=gcd(m,dn)m,q=gcd(m,dn)dn,显然pq互质。
k = ∑ i = 1 m [ p ∣ i q ] = m p = g c d ( m , n d ) k=\sum_{i=1}^m[p\mid iq]=\frac{m}{p}=gcd(m,\frac{n}{d}) k=i=1m[piq]=pm=gcd(m,dn)
\quad g ( d ) = m d − 1 ∗ g c d ( m , n d ) g(d)=m^{d-1}*gcd(m,\frac{n}{d}) g(d)=md1gcd(m,dn)。而 g ( d ) = ∑ d ′ ∣ d f ( d ′ ) g(d)=\sum_{d'\mid d}{f(d')} g(d)=ddf(d),由莫比乌斯反演有 f ( d ) = ∑ d ′ ∣ d μ ( d d ′ ) g ( d ′ ) f(d)=\sum_{d'\mid d}\mu(\frac{d}{d'}){g(d')} f(d)=ddμ(dd)g(d)
\quad a n s ( n ) = ∑ d ∣ n f ( d ) d ,去掉每个循环节同构 ( 123123 , 231231 和 312312 算一种 ) = ∑ d ∣ n 1 d ∑ d ′ ∣ d μ ( d d ′ ) g ( d ′ ) = ∑ d ∣ n 1 d ∑ d ′ ∣ d μ ( d d ′ ) m d ′ − 1 ∗ g c d ( m , n d ′ ) ans(n)=\sum_{d\mid n}\frac{f(d)}{d},去掉每个循环节同构(123123,231231和312312算一种)\\=\sum_{d\mid n}\frac{1}{d}\sum_{d'\mid d}\mu(\frac{d}{d'}){g(d')}\\=\sum_{d\mid n}\frac{1}{d}\sum_{d'\mid d}\mu(\frac{d}{d'})m^{d'-1}*gcd(m,\frac{n}{d'}) ans(n)=dndf(d),去掉每个循环节同构(123123,231231312312算一种)=dnd1ddμ(dd)g(d)=dnd1ddμ(dd)md1gcd(m,dn),交换枚举顺序
= ∑ d ∣ n m d − 1 ∗ g c d ( m , n d ) ∑ d ∣ t 1 t μ t d =\sum_{d|n}m^{d-1}*gcd(m,\frac{n}{d})\sum_{d\mid t}\frac{1}{t}\mu{\frac{t}{d}} =dnmd1gcd(m,dn)dtt1μdt,发现t没用,转成枚举d的k倍数
= ∑ d ∣ n m d − 1 ∗ g c d ( m , n d ) ∑ k ∣ n d 1 k d μ ( k ) = ∑ d ∣ n m d − 1 ∗ g c d ( m , n d ) ∗ 1 d ∑ k ∣ n d μ ( k ) k =\sum_{d|n}m^{d-1}*gcd(m,\frac{n}{d})\sum_{k\mid \frac{n}{d}}\frac{1}{kd}\mu{(k)}\\=\sum_{d|n}m^{d-1}*gcd(m,\frac{n}{d})*\frac{1}{d}\sum_{k\mid \frac{n}{d}}\frac{\mu(k)}{k} =dnmd1gcd(m,dn)kdnkd1μ(k)=dnmd1gcd(m,dn)d1kdnkμ(k)
后面的 μ ( k ) k \frac{\mu(k)}{k} kμ(k)的狄利克雷前缀和可以O(nlogn)预处理出来,这样对于每个ans(n)只要枚举d,总复杂度O(nlogn)

const int N=1e5+5;
const int mod=998244353;
const double eps=1e-8;
int n,m;
int ans[N];
int v[N],p[N],cnt,ni[N];
int mu[N],eu[N],S_mu[N];
std::vector<int> factor[N];
ll qsm(int a,int b){
    ll ans=1,tmp=a;
    while( b ){
        if( b&1 ) ans = (ans * tmp)%mod;
        tmp = tmp * tmp%mod;
        b>>=1;
    }
    return ans;
}
void shai(int n){
_for(i,2,n){
    v[1]=1;
    eu[1]=1;
    mu[1]=1;
    if (!v[i]) {
        p[++cnt] = i;
        mu[i] = -1;
        eu[i] = i - 1;
        v[i]=i;
    }
    _for(j, 1, cnt){
        if (i * p[j] > n)break;
        v[i * p[j]] = p[j];
        if (i % p[j] == 0){
            mu[i*p[j]] = 0;//存在平方因子
            eu[i * p[j]] = eu[i] * p[j];
            break;
        }
        mu[i * p[j]] = -mu[i];
        eu[i * p[j]] = eu[i] * (p[j] - 1);
        }
    }
}
void ini(int n){
    _for(i,1,n) {
        for(int j=i ;j<=n  ;j+=i){
            factor[j].push_back(i);
            S_mu[j]  = (S_mu[j] + mod + mu[i]*ni[i]%mod)%mod;
        }
    }
}
void get_ni(int n){
    ni[0] = ni[1]=1;//0和1逆元
    _for(i,2,n){
        ni[i] = ((mod-mod/i)*ni[mod%i])%mod;
    }
    return;
}
void solve(){
    cin>>n>>m;
    _for(i,1,n){
        for(int j:factor[i]){
            ans[i] = (ans[i] + mod + qsm(m,j-1)*__gcd(m,i/j)%mod*ni[j]%mod*S_mu[i/j]%mod)%mod;
        }
    }
    _for(i,1,n) {
        cout<<ans[i]<<" \n"[i==n];
        ans[i]=0;
    }
}
signed main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif  
    IOS;
    get_ni(1e5);
    shai(1e5);
    ini(1e5);
    int T;cin>>T;
    while( T-- ) solve();
    AC; 
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值