XSY3306alpha - 线段树+分治NTT

Posted dcdcbigbig

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XSY3306alpha - 线段树+分治NTT相关的知识,希望对你有一定的参考价值。

题目来源:noi2019模拟测试赛(一)

题意:

技术分享图片

技术分享图片

题解:

这场三道神仙概率期望题……orzzzy

这题暴力$O(n^2)$有30分,但貌似比正解更难想……(其实正解挺好想的)

注意到一次操作实际上就是在一段区间里乘上了一个形如$px+(1-p)$的多项式,设把所有多项式合并得到一个多项式$F(x)$,那么我们要求的答案实际上就是:

$$[x^k]F(x)$$

那么可以先离散化坐标,然后开一棵线段树,用vector维护每个点(即最小不可再分的区间)上要乘的多项式,最后dfs一遍线段树,用分治NTT合并每个点自身的多项式,再合并子树的多项式即可。

口胡起来很简单但是写起来很恶心……

代码:

NTT写的挫,人傻自带大常数,跑了4.3s

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<vector>
  6 #include<cmath>
  7 #include<queue>
  8 #define inf 2147483647
  9 #define eps 1e-9
 10 #define mod 998244353
 11 #define G 3
 12 using namespace std;
 13 typedef long long ll;
 14 typedef double db;
 15 struct task{
 16     int l,r,p;
 17 }t[50001];
 18 struct node{
 19     int l,r;
 20 }tr[400001];
 21 int n,k,cnt=0,tn=0,nw[10],tmp[100001],lsh[100001],ans[50][50001];
 22 vector<int>v[400001];
 23 namespace Poly{
 24     namespace NTT{
 25         int bit,bitnum,rev[200001],W[200001][2];
 26         int fastpow(int x,int y){
 27             int ret=1;
 28             for(;y;y>>=1,x=(ll)x*x%mod){
 29                 if(y&1)ret=(ll)ret*x%mod;
 30             }
 31             return ret;
 32         }
 33         void pre(){
 34             int rG=fastpow(G,mod-2);
 35             for(int i=1;i<=17;i++){
 36                 W[1<<i][0]=fastpow(G,(mod-1)/(1<<i));
 37                 W[1<<i][1]=fastpow(rG,(mod-1)/(1<<i));
 38             }
 39         }
 40         void getr(int l){
 41             for(bit=1,bitnum=0;bit<l;bit<<=1,bitnum++);
 42             for(int i=1;i<bit;i++){
 43                 rev[i]=(rev[i>>1]>>1)|((i&1)<<(bitnum-1));
 44             }
 45         }
 46         void ntt(int *s,int op){
 47             for(int i=1;i<bit;i++){
 48                 if(i<rev[i])swap(s[i],s[rev[i]]);
 49             }
 50             for(int i=1;i<bit;i<<=1){
 51                 int w=W[i<<1][op==-1];
 52                 for(int p=i<<1,j=0;j<bit;j+=p){
 53                     int wk=1;
 54                     for(int k=j;k<i+j;k++,wk=(ll)wk*w%mod){
 55                         int x=s[k],y=(ll)s[k+i]*wk%mod;
 56                         s[k]=(x+y)%mod;
 57                         s[k+i]=(x-y+mod)%mod;
 58                     }
 59                 }
 60             }
 61             if(op==-1){
 62                 int rb=fastpow(bit,mod-2);
 63                 for(int i=0;i<bit;i++){
 64                     s[i]=(ll)s[i]*rb%mod;
 65                 }
 66             }
 67         }
 68     }
 69     int A[200001],B[200001];
 70     void getmul(int *s,int *a,int *b,int len1,int len2){
 71         for(int i=0;i<=len1;i++)A[i]=a[i];
 72         for(int i=0;i<=len2;i++)B[i]=b[i];
 73         NTT::getr((len1+len2)*2);
 74         for(int i=len1+1;i<NTT::bit;i++)A[i]=0;
 75         for(int i=len2+1;i<NTT::bit;i++)B[i]=0;
 76         NTT::ntt(A,1);
 77         NTT::ntt(B,1);
 78         for(int i=0;i<NTT::bit;i++){
 79             s[i]=(ll)A[i]*B[i]%mod;
 80         }
 81         NTT::ntt(s,-1);
 82     }
 83     void mul(int l,int r,int nw,int *s){
 84         if(l==r){
 85             s[0]=(mod-v[nw][l]+1);
 86             s[1]=v[nw][l];
 87             return;
 88         }
 89         int mid=(l+r)/2;
 90         mul(l,mid,nw,s);
 91         mul(mid+1,r,nw,s+mid-l+3);
 92         getmul(s,s,s+mid-l+3,mid-l+1,r-mid);
 93     }
 94 }
 95 void updata(int l,int r,int u,int L,int R,int p){
 96     if(L<=tr[l].l&&tr[r].r<=R){
 97         v[u].push_back(p);
 98         return;
 99     }
100     int mid=(l+r)/2;
101     if(L<=tr[mid].r)updata(l,mid,u*2,L,R,p);
102     if(tr[mid+1].l<=R)updata(mid+1,r,u*2+1,L,R,p);
103 }
104 int dfs(int l,int r,int u,int x){
105     int mid=(l+r)/2,L,R,mx;
106     if(l<r){
107         L=dfs(l,mid,u*2,x);
108         R=dfs(mid+1,r,u*2+1,x+1);
109         mx=max(L,R);
110     }
111     if(v[u].size()){
112         Poly::mul(0,v[u].size()-1,u,tmp);
113     }else tmp[0]=1;
114     if(l==r){
115         nw[0]=(tr[l].r-tr[l].l+1);
116         Poly::getmul(ans[x],nw,tmp,0,v[u].size());
117         return v[u].size();
118     }
119     for(int i=L+1;i<=mx;i++)ans[x][i]=0;
120     for(int i=R+1;i<=mx;i++)ans[x+1][i]=0;
121     for(int i=0;i<=mx;i++){
122         ans[x][i]=(ans[x][i]+ans[x+1][i])%mod;
123     }
124     Poly::getmul(ans[x],ans[x],tmp,mx,v[u].size());
125     return v[u].size()+mx;
126 }
127 int main(){
128     scanf("%d",&n);
129     Poly::NTT::pre();
130     for(int i=1;i<=n;i++){
131         scanf("%d%d%d",&t[i].l,&t[i].r,&t[i].p);
132         lsh[++cnt]=t[i].l;
133         lsh[++cnt]=t[i].r+1;
134     }
135     scanf("%d",&k);
136     lsh[++cnt]=1;
137     lsh[++cnt]=233333333;
138     sort(lsh+1,lsh+cnt+1);
139     cnt=unique(lsh+1,lsh+cnt+1)-lsh-1;
140     for(int i=2;i<=cnt;i++){
141         tr[++tn].l=lsh[i-1];
142         tr[tn].r=lsh[i]-1;
143     }
144     for(int i=1;i<=n;i++){
145         updata(1,tn,1,t[i].l,t[i].r,t[i].p);
146     }
147     dfs(1,tn,1,0);
148     printf("%d",ans[0][k]);
149     return 0;
150 }

以上是关于XSY3306alpha - 线段树+分治NTT的主要内容,如果未能解决你的问题,请参考以下文章

PLAN OF HEOI(unfinished)

xsy2274 平均值 线段树

xsy1122 路径 点分治+trie

XSY2569火神的鱼(线段树+树状数组)

XSY2538/HDU6155Subsequence Count(矩阵乘法+线段树)

[XSY 1129] flow 最小割 树链剖分 线段树优化建图