jzoj5347. 【NOIP2017提高A组模拟9.5】遥远的金字塔 容斥

来源:互联网 发布:大学生数据统计分析 编辑:程序博客网 时间:2024/05/17 09:16

题意:给出n,m,总共有n+1个位置,第n+1个位置上固定为m,要求在前n个位置上填不大于m的正整数,然后在数轴上的0点有一个球,第i次走的步数可以是第i个位置上的数或者其相反数(后退)。要求最后能走到1.问有多少种方法。

我仿佛是个丝薄。。明明这题更水偏偏要去搞DP。。
可以手玩或者通过扩欧证明得一个合法的序列一定他的总gcd=1。
那么我们可以发现,要求总序列gcd!=1,肯定是整个数列都是m的质因数的倍数
枚举m的质因数x,那么1-m中有m/x个x的倍数,减去就好了。
问题是会减重,这怎么办?当然是容斥大法好啊。
2^tot次方枚举每个质因数是否选择,偶加奇减。可能这样子有点模糊我举个例子。
假设我现在是n=2,m=6
x=2,3。
那么我不选择任何质因数的时候就是总方案数,m^n.
选择两个质因数的贡献是(m/2/3)^2,这里的2次方是因为有两个数,题解中说的有些歧义= =,实际上是每个位置我们都可以取当前m/总乘积这么多个数,所以总共n个位置方案数当然是(m/总乘积)^tmp。
细节的话dfs也可以,直接枚举二进制状态也可以,常数上明明应该dfs大一点,但是inline全开以后差不多= =

#include<cstdio>#include<algorithm>#include<cstring>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;typedef long long ll;const int N=1e5+5;const int mo=1e9+7;ll n,m,p[N],tot;ll ans;inline ll pow(ll a,ll b){    ll ret=1;    while (b)    {        if (b&1)ret=1ll*ret*a%mo;        a=1ll*a*a%mo;        b>>=1;    }    return ret%mo;}inline void dfs(int x,int count,ll mul){    if (x==tot+1)    {        int c=count%2==1?-1:1;        ans=(ans+1ll*c*pow(m/mul%mo,n)%mo+mo)%mo;        return;    }    dfs(x+1,count,mul);    dfs(x+1,count+1,mul*p[x]);}int main(){    freopen("heal.in","r",stdin);    freopen("heal.out","w",stdout);    scanf("%lld%lld",&n,&m);    ll k=m;    for(int i=2;i*i<=k;i++)    {        if (k%i==0)        {            p[++tot]=i;            while (k%i==0)k/=i;        }    }if (k>1)p[++tot]=k;    //ans=pow(m,n);    dfs(1,0,1);    printf("%lld\n",ans);}
阅读全文
0 0
原创粉丝点击