bzoj1213: [HNOI2004] High precision open root

Commemorate this disgusting high-precision question that made me hand in countless times.
This is a question in a middle school simulation competition.

answer:

I started this question with ordinary high-precision multiplication, and then I made the following changes:
1. I used FFT, but I got T
2. Pressed the bit, passed the first data, but I got WA on bzoj
3. Consider To the accuracy error, I changed FFT to NTT, and the result was still WA
4. I asked the teacher for the data, and found that there is a point n is 0, which needs to be judged specially, and then Luogu A, bzojT is
5. It is found that the pressure position can only be at most If you press 3 places, if you have more than 3 people, you will get WA, so I asked the big guys in the bzoj group to change the modulus to a larger one. I used the program for judging prime numbers to find out some modulus larger than 998244353, and they meet the modulus that can be divided by 2^k after subtracting 1. As a result, some inverse elements are difficult to find, and some are not large enough, so I can't find them. For a better modulus, you can only give up the optimization from the pressure bit.
6. Suddenly thought that you can use an inline function, but it is of no use, or T is dropped
7. I enumerate the numbers to be filled from high to low, easy It is found that when filling the high bits, the low bits are all 0, which can be optimized here, and then finally passed

Standard range:

#include<bits/stdc++.h>
typedef long long ll;
const int K=3,N=40003/K,M=pow(10,K),p=998244353,g=3,gi=332748118;
int m,i,l,r,L,lim,re[N],f[11],a[N],b[N],inv;
char s[10003];
struct NUM{
    int t,a[N];
}x,A;
inline int pls(int x,int y){x+=y;return x>=p?x-p:x;}
inline int dec(int x,int y){x-=y;return x<0?x+p:x;}
inline int mul(int x,int y){return (ll)x*y%p;}
inline int pow(int x,int y){
    int ans=1;
    for (;y;y>>=1,x=mul(x,x))
        if (y&1) ans=mul(ans,x);
    return ans;
}
inline void ntt(int *A,int opt){
    for (int i=0;i<lim;i++)
        if (i<re[i]) A[i]^=A[re[i]],A[re[i]]^=A[i],A[i]^=A[re[i]];
    int pp=p-1>>1;
    for (int mid=1;mid<lim;mid<<=1,pp>>=1){
        int wn=pow((opt==1)?g:gi,pp);
        for (int R=mid<<1,j=0;j<lim;j+=R){
            int w=1;
            for (int k=0;k<mid;k++,w=mul(w,wn)){
                int x=A[j+k],y=mul(w,A[j+(k|mid)]);
                A[j+k]=pls(x,y);
                A[j+(k|mid)]=dec(x,y);
            }
        }
    }
    if (opt==-1)
        for (int i=0;i<lim;i++) a[i]=mul(a[i],inv);
}
inline NUM mul(NUM x,NUM y,int t1,int t2){
    for (int i=0;i<x.t-t1;i++) a[i]=x.a[i+t1];
    for (int i=0;i<y.t-t2;i++) b[i]=y.a[i+t2];
    lim=1;L=0;
    for (;lim<x.t+y.t-t1-t2;lim<<=1,L++);
    for (int i=0;i<lim;i++) re[i]=(re[i>>1]>>1)|((i&1)<<(L-1));
    for (int i=x.t-t1;i<lim;i++) a[i]=0;
    for (int i=y.t-t2;i<lim;i++) b[i]=0;
    inv=pow(lim,p-2);
    ntt(a,1);ntt(b,1);
    for (int i=0;i<lim;i++) a[i]=mul(a[i],b[i]);
    ntt(a,-1);x.t+=y.t;
    for (int i=0;i<=t1+t2;i++) x.a[i]=0;
    for (int i=t1+t2;i<x.t;i++) x.a[i]+=a[i-t1-t2],x.a[i+1]=x.a[i]/M,x.a[i]%=M;
    while (x.t && !x.a[x.t-1]) x.t--;
    return x;
}
inline NUM pow(NUM x,int y,int t1){
    NUM z;
    int t2=0;
    if (t1<0) t1=0;
    z.t=z.a[0]=1;
    for (;y;y>>=1,x=mul(x,x,t1,t1),t1<<=1)
        if (y&1) z=mul(z,x,t2,t1),t2+=t1;
    return z;
}
inline bool operator >=(NUM x,NUM y){
    if (x.t!=y.t) return x.t>y.t;
    for (int i=x.t-1;i>=0;i--)
        if (x.a[i]!=y.a[i]) return x.a[i]>y.a[i];
    return 1;
}
inline void print(NUM x){
    for (int i=x.t-1;i>=0;i--){
        if (i<x.t-1){
            int k=(int)log10(x.a[i])+1;
            if (!x.a[i]) k=0;
            for (int j=0;j<K-k;j++) putchar('0');
        }
        if (x.a[i]) printf("%d",x.a[i]);
    }
}
int main(){
    scanf("%d\n",&m);
    gets(s);//在洛谷里一定要scanf
    f[0]=1;
    for (i=1;i<9;i++) f[i]=f[i-1]*10;
    A.t=strlen(s);
    if (A.t==1 && s[0]=='0'){
        putchar('0');
        return 0;
    }
    for (i=A.t-1;i>=0;i--) A.a[(A.t-1-i)/K]+=(s[i]^48)*f[(A.t-1-i)%K];
    A.t=((A.t-1)/K)+1;
    x.t=(A.t-1)/m+1;
    for (i=x.t-1;i>=0;i--){
        l=0;r=M-1;
        while (l<r){
            x.a[i]=l+r+1>>1;
            if (A>=pow(x,m,i)) l=x.a[i];
            else r=x.a[i]-1;
        }
        x.a[i]=l;
    }
    print(x);
}

This program is not even an ordinary high-precision multiplier, and it is speechless. . . Maybe it's because they all press 8, and I can only press 3. Although
this question took me a lot of time, it still has a lot of gains. It's a good question.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326822416&siteId=291194637