[examination summary] January 7, 2022

Posted by sintax63 on Fri, 07 Jan 2022 10:10:47 +0100

Guessing game

According to the idea of Hunter killing, the situation with a draw is changed to play until the outcome is determined. At this time, the probability of victory is \ (\ frac{win}{win+lose} \)

If the maximum \ (\ frac{win}{win+lose} \) problem can be found, consider using \ (\ rm DP \) to find the winning rate, that is, let \ (f_i \) represent the winning rate when the number of winning and losing games is \ (I \)

The equation is \ (f {I} = f {I + 1} Win + F {I-1} lose \), initialization \ (f {M1} = 1, f {- M2} = 0 \), which can be solved by Gaussian elimination

Ah, I found that I read the wrong title yesterday. The meaning of the title is that one side wins \ (m1/m2 \) games more than the other. I read it as winning in a row

The remaining problem is to solve \ (\ max\frac{win}{win+lose} \), which is equivalent to finding the maximum \ (K \) to meet \ (win=k \times lose \), and consider using 01 score programming

Suppose it is necessary to judge whether $win= k\times lose $is legal, then win \ (1 \) points and lose \ (K \) points. If the final score of the first person \ (\ ge 0 \), it means that the probability of victory is greater than or equal to \ (K \) times the probability of failure

Let \ (f {i, j} \) represent the maximum product score when the difference between the victory and defeat of both sides is \ (j \) before the \ (i \) round, in reverse order \ (\ rm DP \), give the stone, scissors or cloth to be transferred, initialize \ (f {n + 1,0} = 0, f {n + 1, [x > 0]} = 1, f {n + 1, [x < 0]} = - K \)

Code Display
const int N=1010;
double a[N][N],res[N],per[N][3];
int m1,m2,n;
inline double Guass(double win){
    double lose=1-win;
    int n=m1+m2-1;
    a[1][1]=1; a[1][2]=-win;
    for(int i=-m2+2;i<=m1-2;++i){
    a[n][n]=1; a[n][n-1]=-lose; a[n][n+1]=win;
    for(int i=1;i<=n;++i){
            for(int j=i+1;j<=n;++j) if(fabs(a[j][i])>1e-9) swap(a[i],a[j]); 
        if(a[i][i]<1e-9) continue;
        for(int j=i+1;j<=n;++j) if(a[j][i]){
            double tmp=a[j][i]/a[i][i];
            for(int k=n+1;k>=i;--k) a[j][k]-=a[i][k]*tmp;
    for(int i=n-1;i>=1;--i){
        for(int j=i+1;j<=n;++j) a[i][n+1]-=a[i][j]*res[j];
    return res[m2];
const int U=1003;
double dp[1010][2010];
inline bool check(double cst){
    rep(i,1,n+1) rep(j,-(n+1),n+1) dp[i+1][j+U]=0;
    for(int i=-(n+1);i<=n+1;++i){
        if(i>0) dp[n+1][i+U]=1;
        if(i==0) dp[n+1][i+U]=0;
        if(i<0) dp[n+1][i+U]=-cst;
    for(int i=n;i;--i){
        for(int j=-i;j<=i;++j){
            double vv=-1e18;
            for(int cho=0;cho<=2;++cho){
                double val=dp[i+1][j+U]*per[i][cho]+dp[i+1][j+1+U]*per[i][(cho+2)%3]+dp[i+1][j-1+U]*per[i][(cho+1)%3];
    return dp[1][U]>=0;
signed main(){
        n=read(); m1=read(); m2=read();
        if(n+m1+m2==0) exit(0);
        for(int i=1;i<=n;++i){
            for(int j=0;j<=2;++j) per[i][j]=read()*1.0/100;
        double l=0,r=1e18;
            double mid=(l+r)/2;
            if(check(mid)) l=mid;
            else r=mid;
    return 0;

Small H love dyeing

\[Ans=\sum_{i=0}^{n-1}H(n-i)\sum_{j=0}^m f_ji^j \]

Where \ (H(len) \) indicates that a sequence with a length of \ (len \) is dyed twice. Each time \ (m \) positions are dyed black, and the first position must be dyed

After the investigation, the following \ (i^j \) is expanded with the second kind of Stirling number:

\[\begin{aligned}&\sum_{i=0}^{n-1}H(n-i)\sum_{j=0}^m f_j\sum_{k=0}^jk!\binom ik \begin{Bmatrix}j\\ k\end{Bmatrix}\\ &=\sum_{i=0}^{n-1} H(n-i)\sum_{j=0}^m f_j\sum_{k=0}^m\binom ik \sum_{l=0}^k(-1)^l\binom k l(k-l)^j\\ &=\sum_{i=0}^{n-1} H(n-i)\sum_{k=0}^m\binom ik \sum_{l=0}^k(-1)^l\binom k l\sum_{j=0}^mf_j (k-l)^j\\ &=\sum_{i=0}^{n-1} H(n-i)\sum_{k=0}^m\binom ik \sum_{l=0}^k(-1)^l\binom k lF(k-l) \end{aligned}\]

If you are a master of algebraic derivation, you can use the method of "enumerating how many balls are stained black" to express \ (H(n-i) \), and then recite the foundation with your powerful combinatorial identity to get the same formula as using combinatorial meaning!

The combinatorial meaning is that a total of several small balls are selected for direct enumeration and blackened. After enumeration, several small balls are selected for coloring. In this way, the first small ball behind is the corresponding \ (i+1 \) and it is also blackened. The expression is as follows:

\[Ans=\sum_{k=0}^m\sum_{t=m}^{2m} \binom {n}{t+k}\binom{t}{m}\binom{m}{2m-t}\sum_{l=0}^k(-1)^l\binom k lF(k-l) \]

With hands \ (\ rm NTT \), it's done

Code Display
const int N=4.2e6+10;
int fac[N],ifac[N],inv[N],comb[N],f[N],n,m,F[N],G[N];
inline int C(int n,int m){return n<m?0:mul(fac[n],mul(ifac[m],ifac[n-m]));}
int r[N],W[N];
inline void NTT(int* f,int lim,int opt){
    for(int i=0;i<lim;++i){
        if(i<r[i]) swap(f[i],f[r[i]]);
    for(int p=2;p<=lim;p<<=1){
        int len=p>>1; W[0]=1; W[1]=ksm(3,(mod-1)/p);
        if(opt==-1) W[1]=ksm(W[1],mod-2);
        for(int j=2;j<len;++j) W[j]=mul(W[j-1],W[1]);
        for(int k=0;k<lim;k+=p){
            for(int l=k;l<k+len;++l){
                int tt=mul(f[l+len],W[l-k]);
    if(opt==-1) for(int i=0,tmp=ksm(lim,mod-2);i<lim;++i) ckmul(f[i],tmp);
    return ;
signed main(){
    n=4e6; fac[0]=inv[0]=1;
    for(int i=1;i<=n;++i) fac[i]=mul(fac[i-1],i);
    for(int i=n;i>=1;--i) ifac[i-1]=mul(ifac[i],i),inv[i]=mul(ifac[i],fac[i-1]);
    n=read(); m=read();
    for(int i=1;i<=3*m;++i){
    for(int i=0;i<=m;++i){
    int lim=1; while(lim<=(m+1)*2) lim<<=1;
    int ans=0;
    NTT(F,lim,1); NTT(G,lim,1); 
    rep(i,0,lim-1) ckmul(F[i],G[i]);
        if(i>m) F[i]=0; else ckmul(F[i],fac[i]);
    while(lim<=(m+1)*3) lim<<=1;
    NTT(F,lim,1); NTT(G,lim,1);
    rep(i,0,lim-1) ckmul(F[i],G[i]);
    for(int s=m;s<=3*m;++s) ckadd(ans,mul(F[s],comb[s]));
    return 0;

B Jun's memory

The calculation of the nested inner layer is essentially a sequence of numbers, taking the module of the cyclic node in the sense of the outer module, and backtracking the fast power of the matrix

In essence, solving the cycle node is to obtain the identity matrix in the sense of \ (\ mod p \) after quickly exponentiating the transfer matrix several times. You can use \ (\ rm BSGS \) to solve it

It is not difficult to find that according to the principle of multiplication, the cyclic node of a composite number is \ (\ rm lcm \) of its prime factor cyclic node, which can be accelerated by reducing the upper bound of the root sign of \ (BSGS \)

I read a written The article of circular section in the sense of Fibonacci module The following conclusions are written:

  • \(5) if there is a quadratic residue in the sense of prime number, then \ (cyc|p-1 \)

  • \(5 \) if there is no quadratic residue in the sense of module, then \ (cyc|(2p+2) \)

  • The cyclic node of the power of modulo prime \ (p^k \) satisfies \ (cyc|cyc(p)p^{k-1} \)

The conclusion is any composite number \ (P \), and the upper bound of cyclic section is \ (6p \)

These derivation processes seem to be applicable to the generalized Fibonacci sequence. If you set \ (g(0)=0,g(1)=1 \) and even find that the \ (n \) item is the \ (2n \) item of Fibonacci sequence, you can probably think that the cyclic section is about \ (3p \)

Code Display
map<int,int> cyc;
struct mat{
    int a[2][2];
    bool operator ==(const mat &b)const{
        return a[0][0]==b.a[0][0]&&a[1][1]==b.a[1][1]&&a[1][0]==b.a[1][0]&&a[0][1]==b.a[0][1];
    mat(){} mat(int A,int b,int c,int d){
        a[0][0]=A; a[0][1]=b; a[1][0]=c; a[1][1]=d;
        return ;
#define ull unsigned long long 
    inline unsigned long long sign(){
        ull res=0,bas=13331;
        rep(i,0,1) rep(j,0,1) res+=a[i][j]*bas,bas=bas*13331;
        return res;
    inline void init(){memset(a,0,sizeof(a));}
int n,a,b,k,p;
inline void Mul(mat &a,mat &b,int mod){
    int c[2][2]={};
    rep(i,0,1) rep(k,0,1) if(a.a[i][k]) rep(j,0,1) c[i][j]+=a.a[i][k]*b.a[k][j];
    rep(i,0,1) rep(j,0,1) a.a[i][j]=c[i][j]%mod;
    return ;
#define E 19260817
struct hashmap{
    struct edge{int val,nxt; mat to;}e[200000];
    int head[E],ecnt;
    vector<int> hs;
    inline void clear(){
        for(auto t:hs) head[t]=0;
        return ;
    inline void insert(mat now,int x){
        ull p;
        if(!head[p]) hs.pb(p);
        return ;
    inline int query(mat now){
        for(int i=head[now.sign()%E];i;i=e[i].nxt){
            if(e[i].to==now) return e[i].val;
        } return -1;
inline int Get(int n,int p){
    mat bas=mat(0,p-1,1,3);
    int vec[2]={a,b};
            int tmp[2]={};
            rep(i,0,1) rep(j,0,1) tmp[j]+=vec[i]*bas.a[i][j];
            rep(i,0,1) vec[i]=tmp[i]%p,assert(vec[i]>=0);
    return vec[0];
inline int find(int x){
    if(x==1) return 1;
    if(cyc.count(x)) return cyc[x];
    int up=x*4,sqr=sqrt(up); 
    mat bas=mat(0,x-1,1,3),now=unit;
    for(int i=0;i<sqr;++i){
        if(now==unit) return cyc[x]=i+1;
    bas=now; Mul(now,now,x);
    for(int i=2;i<=up/sqr;++i){
        int rr=hs.query(now);
            return cyc[x]=i*sqr-rr;
inline int gcd(int x,int y){return y?gcd(y,x%y):x;}
inline int Div(int p){
    if(p==1) return 1;
    int res=-1;
    for(int i=2;i*i<=p;++i) if(p%i==0){
        int ee=1;
        while(p%i==0) ee*=i,p/=i;
        int gg=find(i)*ee/i;
        if(~res) res=res/gcd(res,gg)*gg;
        else res=gg;
        int gg=find(p);
        if(~res) res=res/gcd(res,gg)*gg;
        else res=gg;
    return res;
inline int F(int n,int k,int p){
    if(k==1) return Get(n,p);
    return Get(F(n,k-1,Div(p)),p);
signed main(){
    int T=read(); while(T--){
        a=read(); b=read(); n=read(); k=read(); p=read();
    return 0;