NOIP模拟测试30「return·one·magic」

magic

题解

首先原式指数肯定会爆$long$ $long$

首先根据欧拉定理我们可以将原式换成$N^{\sum\limits_{i=1}^{i<=N} [gcd(i,N)==1] C_{G}^{i}  \%phi(p)}\%p$

根据欧拉函数是积性的得出$phi(54184622)=phi(2)*phi(27092311)$

然后$phi(27092311)=27092310$  $phi(2)=1$所以$phi(54184622)=27092310$

于是我们现在要求的就是$N^{\sum\limits_{i=1}^{i<=N} [gcd(i,N)==1] C_{G}^{i}  \%27092310}\%p$

$27092310=2*3*5*7*129011$然后裸的$crt$求组合数板子求就完了

注意:你要预处理出阶乘和逆元,否则会超时

代码

#include<bits/stdc++.h>
#define ll long long
#define A 333333
ll k,p,n,g;
//phi(54184622)=27092310
//27092310=2*3*5*7*129011
ll w[7]={0,2,3,5,7,129011,54184622},jie[6][A],ni[6][A],dl[A],b[A];
ll exgcd(ll a,ll b,ll &x,ll &y){
    if(b==0){
        x=1;y=0;
        return a;
    }
    ll gcd=exgcd(b,a%b,x,y);
    ll t=x;
    x=y;
    y=t-a/b*y;
    return gcd;
}
ll meng(ll x,ll k,ll cix){
    ll ans=1;
    for(;k;k>>=1,x=x*x%w[cix])
        if(k&1)
            ans=ans*x%w[cix];
    return ans;
}
ll china(){
    ll x,y,a=0,m,n=1;
    for(ll i=1;i<=5;i++)
        n*=w[i];
    for(ll i=1;i<=5;i++){
        m=n/w[i];
        exgcd(w[i],m,x,y);
        a=(a+y*m*b[i])%n;
    }
    if(a>0) return a;
    return a+n;
}
ll gcd(ll x,ll y){
    if(y==0) return x;
    return gcd(y,x%y);
}
ll jic(ll n,ll m,ll cix){
    if(m>n) return 0;
    if(m==0) return 1;
    return jie[cix][n]%w[cix]*ni[cix][n-m]%w[cix]*ni[cix][m]%w[cix];
}
ll lucas(ll n,ll m,ll cix){
    if(n==0)return 1;
    return jic(n%w[cix],m%w[cix],cix)*lucas(n/w[cix],m/w[cix],cix)%w[cix];
}
using namespace std;
int main()
{
    scanf("%lld%lld",&n,&g);    
    for(ll i=1;i<=min(g,n);i++){
        if(gcd(i,n)==1)
            dl[++dl[0]]=i;
    }
    for(ll i=1;i<=5;i++){
        jie[i][0]=1;
        ni[i][0]=1;
        for(ll j=1;j<w[i];j++)
            jie[i][j]=jie[i][j-1]*j%w[i];
        ni[i][w[i]-1]=meng(jie[i][w[i]-1],w[i]-2,i);
        for(ll j=w[i]-2;j>=1;j--)
            ni[i][j]=ni[i][j+1]*(j+1)%w[i];
        for(ll j=1;j<=dl[0];j++)
            (b[i]+=lucas(g,dl[j],i))%=w[i];
    }
    ll j=china();
    ll k=meng(n,j,6);
    cout<<k<<endl;
    //模w「i」 剩余b「i」    
}
View Code

one

题解

美妙的约瑟夫问题,

范围特别大考虑线性推

然而我懒的说了

代码特别简单,只是上文稍做修改

代码

#include<bits/stdc++.h>
using namespace std;
#define ll int
#define A 1000000
ll ans,t,n;
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        ans=0;
        for(ll i=n-1;i>=0;i--)
            ans=(ans+i)%(n-i+1);
        printf("%d\n",ans+1);
    }
}
View Code

return

题解

这是道语文题,这一定是一个语文题,一定是这样

其实它是让你求前趋后继

那么这个题难点就在于怎么在作者给出题干中看出是前趋后继

那么我们看题干

  

     $0-2^{31}$范围内

 

 我真的没看出来这是求前趋后继,$pdf$上没给样例解释

posted @ 2019-08-23 16:44  znsbc  阅读(176)  评论(0编辑  收藏  举报