bzoj5193 [Usaco2018 Feb]Cow Gymnasts

http://www.elijahqi.win/2018/03/06/bzoj5193/
Description

厌倦了农场生活,奶牛们变卖了所有尘世的财产,加入了一支巡回马戏团。到现在为止,奶牛们已经能够进行简单
的表演了:耍火把、走钢丝、骑独轮车——没什么是拥有灵巧蹄子的奶牛做不到的。但是,马戏团指挥想要为他们
的下一次演出创作一个更加激动人心的表演。新的表演所用的舞台由N个围成一圈的平台组成。在每个平台上,1至
N头奶牛叠成一摞,一头叠在一头上面。当指挥给出信号的时候,每摞奶牛同时顺时针落下,最下面的奶牛不动,
在她上面的奶牛顺时针移动一个平台,再上面的奶牛顺时针移动两个平台,等等。作为技艺高超的体操家,奶牛们
明白她们在这个表演的技术方面没有任何问题。不同摞的奶牛在下落的过程中不会相互“干扰”,所以每头奶牛都
会落在预期的平台上。然后所有落在同一平台上的奶牛又会重新叠成一摞,这次她们不会再落下来。指挥认为,如
果在奶牛们落下之后,每个平台上新的那一摞奶牛的数量和原来这个平台上的那一摞奶牛数量相等的话,这次表演
就会格外激动人心。我们把满足这种性质的各摞奶牛的数量排列称为是“魔幻的”。请帮助奶牛计算魔幻的排列数
。由于这个数字可能非常大,计算该数mod 10^9+7的余数。两个排列被认为是不同的,如果这两个排列在任何一个
平台上分配了不同数量的奶牛。

Input

输入包含一个整数N(1≤N≤10^12)。

Output

输出一个整数,为魔幻的排列数mod 10^9+7的余数。

Sample Input

4
Sample Output

6
当N=4时,魔幻的排列有(1,1,1,1),(2,2,2,2),(3,3,3,3),
(4,4,4,4),(2,3,2,3),以及(3,2,3,2)。
HINT

Source

Platinum
官方题解
假设台上最少的牛只有m只并且记当前台为i
ji(modg) j ≡ i ( mod g ) , g=gcd(N,m) g = gcd ( N , m )
台子上所有的牛也必定是m只 其他台子上的牛是m+1只 怎么证明的就是考虑周期性 每一个对其他的影响这样重复算的 为什么是gcd(n,m) 可以考虑为是小循环和大循环多少次之后可以重复
那么答案便是
ANS=12N+Nm=12gcd(m,N) A N S = 1 − 2 N + ∑ m = 1 N 2 gcd ( m , N ) m=n的情况单独计算所以1-2^n
考虑枚举g
ANS=12N+gN2gφ(Ng). A N S = 1 − 2 N + ∑ g ∣ N 2 g φ ( N g ) .
φ(x=pe11pe22peii)=x(p11)(p21)(pi1)p1p2pi. φ ( x = p 1 e 1 p 2 e 2 ⋯ p i e i ) = x ∗ ( p 1 − 1 ) ( p 2 − 1 ) ⋯ ( p i − 1 ) p 1 p 2 ⋯ p i .
枚举的时候更改了一下顺序 就变成我去枚举 φ φ 里面的东西 那么可以知道这样枚举的话我只需要 如果g不增加 φ φ 里也不增加否则 增加质因子之后g同样需要枚举着增加

#include<vector>
#include<cstdio>
#include<algorithm>
#define ll long long
#define mod 1000000007
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline ll read(){
    ll x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();}
    while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
    return x*f;
}
inline ll pow(ll base,ll t){
    ll tmp=1;
    for (;t;t>>=1,(base*=base)%=mod) 
        if (t&1) (tmp*=base)%=mod;return tmp;
}
vector<ll>prime;vector<int> nm;ll n,ans;
inline void dfs(int x,ll g,ll up,ll down){
    if (x==prime.size()){
        if (g==1) return;// m=n的情况单独计算
        ans+=pow(2,n/g)*((g/down*up)%mod)%mod;ans%=mod;return;
    }dfs(x+1,g,up,down);up*=(prime[x]-1);down*=prime[x];
    for (int i=1;i<=nm[x];++i) g*=prime[x],dfs(x+1,g,up,down);
}
int main(){
    freopen("gymnasts.in","r",stdin);
    freopen("gymnasts.out","w",stdout);
    n=read();ll x=n;
    for (int i=2;(ll)i*i<=n;++i){int tmp=0;
        if (x%i) continue;prime.push_back(i);
        while(x%i==0) ++tmp,x/=i;nm.push_back(tmp);
    }if (x>1) prime.push_back(x),nm.push_back(1);
    dfs(0,1,1,1);ans-=(n-1)%mod;(ans+=1+mod)%=mod;
    printf("%lld\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值