【LOJ565】【LibreOJ Round #10】mathematican 的二进制
SOL:
1.我们发现如果进行k次操作,最后结果为v,那么代价=2*k-bitcount(v)
2.我们发现ans=2* 概率和 - bitcount(所有操作的数)的期望
3.所有操作的顺序互相无关。
那么我们按位操作,从低向高DP。
同一位上分治NTT,不同位上DP+NTT转移。
#include<bits/stdc++.h> #define mo 998244353 #define LL long long #define pii pair<int,int> #define x first #define y second #define pb push_back #define N 800207 using namespace std; #define sight(x) ('0'<=x&&x<='9') inline void read(int &x){ static char c; for (c=getchar();!sight(c);c=getchar()); for (x=0;sight(c);c=getchar())x=x*10+c-48; } inline LL qsm(LL x,LL y=mo-2){ static LL anw; for (anw=1;y;y>>=1,x=x*x%mo) if (y&1) anw=anw*x%mo; return anw; } LL l[N],n[N];int D[N]; void Pre() { for (int i=1;i<N;i++) l[i]=qsm(3,(mo-1)/i/2),n[i]=qsm(l[i]); } LL wn,w,Xx,Yy; inline void NTT(vector<LL> &X,int x,int m){static LL gg; m=1<<m;gg=qsm(m); for (int i=0;i<m;i++) if (i<D[i]) swap(X[i],X[D[i]]); for (int i=1;i<m;i<<=1) { wn=x?l[i]:n[i]; w=1; for (int j=0;j<m;j+=i<<1,w=1) for (int k=j;k<j+i;k++,w=w*wn%mo) { Xx=X[k]; Yy=X[k+i]*w%mo; X[k]=(Xx+Yy)%mo; X[k+i]=(Xx-Yy+mo)%mo; } } if (!x) for (int i=0;i<m;i++) X[i]=X[i]*gg%mo; } struct Poly{ vector<LL> poly; int len; Poly() {len=0; poly.clear(); poly.pb(1);} void clear(){len=0; poly.clear(); poly.pb(1);} void mul(Poly &A,Poly &B){ static int m; len=B.len+A.len; for (m=0;1<<m<=len;m++); poly.resize(1<<m); A.poly.resize(1<<m); B.poly.resize(1<<m); for (int i=1;i<(1<<m);i++) D[i]=D[i>>1]>>1|((i&1)<<m-1); NTT(A.poly,1,m); NTT(B.poly,1,m); for (int i=0;i<(1<<m);i++) poly[i]=A.poly[i]*B.poly[i]%mo; NTT(poly,0,m); A.clear(); B.clear(); } void out() { for (int i=len;~i;i--) printf("%lld ",poly[i]);puts(""); } }P[N],g[N],Pta,*f=g+1; pii p[N]; #define Mid (l+r>>1) void sol(int no,int l,int r){ if (l==r) { P[no].len=1; P[no].poly[0]=1+mo-p[l].y; P[no].poly.pb(p[l].y); return;} sol(no<<1,l,Mid),sol(no<<1|1,Mid+1,r); P[no].mul(P[no<<1],P[no<<1|1]); } int ll,r; int Nn,m; LL ans; signed main () { // freopen("c.in","r",stdin); Pre(); //f[0].poly.pb(1); read(Nn); read(m); for (int i=1;i<=m;i++) read(p[i].x),read(ll),read(r),p[i].y=1ll*ll*qsm(r)%mo, ans+=2*p[i].y; sort(p+1,p+m+1); ans%=mo; r=0; for (int i=0;i<=Nn+20;i++) { ll=r+1; if (p[ll].x==i) while (p[r+1].x==i&&r<m) r++; Pta.poly.resize((f[i-1].len>>1)+1); Pta.len=f[i-1].len>>1; assert(f[i-1].poly.size()>=f[i-1].len+1); for (int j=0;j<=f[i-1].len;j+=2) { Pta.poly[j>>1]=f[i-1].poly[j]; if (j+1<=f[i-1].len) ans-=f[i-1].poly[j+1],ans%=mo, Pta.poly[j>>1]+=f[i-1].poly[j+1],Pta.poly[j>>1]%=mo; } if (p[ll].x==i) sol(1,ll,r); f[i].mul(P[1],Pta); } printf("%lld\n",(ans%mo+mo)%mo); return 0; }