CSUST 第四次周赛 简单博弈(卡特兰数+唯一分解)

CSUST 第四次周赛 简单博弈(卡特兰数+唯一分解)

Alice和Bob这两个熊孩子又一次聚集在一起玩游戏。

这次的游戏是一个填字符的游戏,游戏规则如下:

在一个拥有x(x为偶数)个空位的数轴上二人轮流填写自己名字的第一个字母,即Alice填A,Bob填B;

Alice为先手,即第一回合是Alice填字,第二回合Bob,第三回合Alice\dotsAlice…
每次填字只能填在数轴上的空位处,不能填写在已经填过的位置;

AliceAlice获胜的条件是对于数轴上每一个空位都满足该位及之前的AA的数量大于等于BB的数量;

结果是在所有空位填完之后才判定,中途如果谁输了游戏仍然继续直到没有空位。

由于Alice智商很高,因此他在游戏开始前先在头脑里面构思出所有二人填字完毕后的情况(注意由于只考虑最后的情况,因此中途的填写顺序忽略,譬如Alice第一步放在第3空位第二步放第4空位与第一步放第4空位第二步放第33空位视为同一种情况),然后计算出其中有多少种情况自己会获胜。现在告诉你n=x/2
问你AliceAlice获胜的所有方案数,由于答案可能很大,因此请输出答案对 10^9 取模后的结果。
Input
输入包含一个整数n(1<=n<=10^6).

Output
输出方案数对 10^9 取模后的结果。
Sample Input 1
2
Sample Output 1
2

看完题 发现又是卡特兰数 难道好心的出题人准备送分 拿着上一场的代码交了一发 wa 发现取模不同 改了取模 还是 wa .意识到不对劲 原来不能求逆元 求逆元 要求 mod 为素数 或者 n+1与mod 互质。

看完学长的题解 要用唯一分解 求(2*n)! / (n)!(n+1)!
然后学了 阶乘唯一分解
普通分解也行 不过要优化



#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=2e6+7;
const int mod=1e9;
bool isprime[maxn];
int temp[maxn];
ll n,k=1;
ll ans=1;
long long poww(long long a,long long b){//快速幂
       long long ans=1;
       while(b>0){
            if(b&1) ans=ans*a%mod;
            a=a*a%mod;
            b>>=1;

       }
      return ans;
}
void sieve(){    //埃式筛
    for(int i=0;i<=maxn;i++)isprime[i]=true;
    isprime[0]=isprime[1]=false;
    for(int i=2;i<=maxn;i++){//从2开始往后筛
        if(isprime[i]){
            for(int j=2*i;j<=maxn;j+=i){
                isprime[j]=false;
            }
        }
    }
}
ll pr[maxn],e1[maxn],e2[maxn];
void init1(ll nn){                    //唯一分解
      for(int i=1;i<k;i++){
         ll p=pr[i];
         while(p<=nn){
            e1[i]+=nn/p;
            p*=pr[i];
         }
     }
}
void init2(ll nn){
      for(int i=1;i<k;i++){
         ll p=pr[i];
         while(p<=nn){
            e2[i]+=nn/p;
            p*=pr[i];
         }
     }
}
int main (){

    cin>>n;
    sieve();
    for(int i=2;i<=2*n;i++){
        if(isprime[i]) pr[k++]=i;
    }
   init1(2*n);
   init2(n);
   init2(n+1);
    for(int i=1;i<k;i++){
        ans=ans*poww(pr[i],e1[i]-e2[i])%mod;
    }
    printf ("%lld\n",ans);
}

普通分解

#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=2e6+7;
const int mod=1e9;
bool isprime[maxn];
int temp[maxn];
ll n;
long long poww(long long a,long long b){//快速幂
       long long ans=1;
       while(b>0){
            if(b&1) ans=ans*a%mod;
            a=a*a%mod;
            b>>=1;

       }
      return ans;
}
void sieve(){    //埃式筛
    for(int i=0;i<=2*n;i++)isprime[i]=true;
    isprime[0]=isprime[1]=false;
    for(int i=2;i<=maxn;i++){//从2开始往后筛
        if(isprime[i]){
            for(int j=2*i;j<=maxn;j+=i){
                isprime[j]=false;
            }
        }
    }
}
int pr[maxn],e1[maxn],e2[maxn];
int main (){
    ll k=1;
    ll ans=1;
    cin>>n;
    sieve();
    for(int i=2;i<=2*n;i++){
        if(isprime[i]) pr[k++]=i;
    }
    for(int i=2;i<=2*n;i++){
        int t=i,j=0;
        while(t!=1){
            j++;
            if(t%pr[j]==0){
               while(t%pr[j]==0){
                  e1[pr[j]]+=1;
                  if(i<=n) e2[pr[j]]+=2;
                  else if(i==n+1) e2[pr[j]]+=1;
                  t/=pr[j];
               }
            }

            if(pr[j]*pr[j]>=t) break;  //这里很重要
        }
        e1[t]+=1;
        if(i<=n) e2[t]+=2;
        else if(i==n+1) e2[t]+=1;
    }
    for(int i=1;i<k;i++){
       // printf ("%lld %lld %lld\n",pr[i],e1[pr[i]],e2[pr[i]]);
        ans=ans*poww(pr[i],e1[pr[i]]-e2[pr[i]])%mod;
    }
    printf ("%lld\n",ans);




}
 if(pr[j]*pr[j]>=t) break;

这里 必须 跳出来 因为到达这一步之后 最后肯定只剩一个 质数(不然会超时)(菜鸡的我 问了 wj 学长才知道的)

线性分解的复杂度低很多 但貌似只适合求 阶乘唯一分解

你可能感兴趣的:(CSUST 第四次周赛 简单博弈(卡特兰数+唯一分解))