2021.8.24考试总结[NOIP47]
T1 prime
发现只需筛小于等于$mid(\sqrt r,k)$的质数,之后用这些质数筛掉区间内不合法的数即可。
$code:$
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 5 namespace IO{ 6 inline int read(){ 7 int x=0,f=1; char ch=getchar(); 8 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 9 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 10 return x*f; 11 } 12 inline void write(int x,char sp){ 13 char ch[20]; int len=0; 14 if(x<0){ putchar('-'); x=~x+1; } 15 do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x); 16 for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp); 17 } 18 } using namespace IO; 19 20 const int NN=1e7+5; 21 int l,r,k,cnt,ans,pri[NN],ext; 22 bool vis[NN],is[NN]; 23 24 void prime(){ 25 for(int i=2;i<=ext;i++){ 26 if(i<=k&&!vis[i]) pri[++cnt]=i; 27 for(int j=1;j<=cnt&&i*pri[j]<=ext;j++){ 28 vis[i*pri[j]]=1; 29 if(!i%pri[j]) break; 30 } 31 } 32 for(int i=1;i<=cnt;i++){ 33 int j=l/pri[i]; 34 if(l!=pri[i]*j) ++j; 35 for(j=max(j,2ll);j*pri[i]<=r;j++) 36 is[j*pri[i]-l]=1; 37 } 38 } 39 40 signed main(){ 41 l=read(); r=read(); k=read(); ext=min((int)sqrt(r),k); 42 prime(); 43 for(int i=l;i<=r;i++) 44 if(!is[i-l]) ans^=i; 45 write(ans,'\n'); 46 return 0; 47 }
T2 sequence
先考虑基础$DP$。
设$f_{i}$表示以$i$为结尾的不同子序列个数。那么每次转移都有$f_i=1+\sum_{j=1}^k f_j$。最终答案为$\sum_{i=1}^k f_i$。
发现转移后大小的固定的,那么为了最大化答案,每次找最小的状态转移。
然后看到$m$的范围,有发现每次$DP$存在规律,考虑矩阵优化。
可以先通过每个值最后出现的位置得到$DP$值取模前的真实大小关系,从大到小排序,构成状态矩阵。
考虑转移矩阵,每次挑最小的转移变为最大的,然后次小变为最小,以此类推。以$k=4$为例:
$\begin{Bmatrix}
f_1\\
f_2\\
f_3\\
f_4\\
1
\end{Bmatrix}\times\begin{Bmatrix}
0 &1 &0 &0 &0 \\
0 &0 &1 &0 &0 \\0 & 0 & 0 & 1 &0 \\
1 &1 &1 &1 &1 \\
0 & 0 & 0 &0 &1
\end{Bmatrix}$
$code:$
1 #include<bits/stdc++.h> 2 #define rin register signed 3 using namespace std; 4 typedef long long LL; 5 6 namespace IO{ 7 inline LL read(){ 8 LL x=0,f=1; char ch=getchar(); 9 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 10 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 11 return x*f; 12 } 13 inline void write(int x,char sp){ 14 char ch[20]; int len=0; 15 if(x<0){ putchar('-'); x=~x+1; } 16 do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x); 17 for(rin i=len-1;~i;i--) putchar(ch[i]); putchar(sp); 18 } 19 } using namespace IO; 20 21 const int NN=1e6+5,p=1000000007; 22 int n,k,a[NN],b[105],lst[105],g[105],cnt,sum,ans; 23 LL m; 24 bool vis[105]; 25 struct node{ 26 int val,lst; 27 node(){} node(int a,int b){val=a,lst=b;} 28 inline bool operator <(const node &x)const{ return lst>x.lst; } 29 }; 30 priority_queue<node> q; 31 32 namespace matrix{ 33 struct mat{ 34 int s[105][105]; 35 void clear(){ memset(s,0,sizeof(s)); } 36 void pre(){ clear(); for(rin i=1;i<=k+1;i++) s[i][i]=1; } 37 }base,f; 38 mat mul(mat x,mat y){ 39 mat res; res.clear(); 40 for(rin i=1;i<=k+1;i++) 41 for(rin j=1;j<=k+1;j++) 42 for(rin u=1;u<=k+1;u++) 43 (res.s[i][j]+=1ll*x.s[i][u]*y.s[u][j]%p)%=p; 44 return res; 45 } 46 void qpow(int b){ 47 } 48 } using namespace matrix; 49 50 void init(){ 51 int cnt=0; 52 f.s[k+1][1]=base.s[k+1][k+1]=1; 53 for(rin i=2;i<=k;i++) base.s[i-1][i]=1; 54 for(rin i=1;i<=k+1;i++) base.s[k][i]=1; 55 while(!q.empty()){ f.s[++cnt][1]=q.top().val; q.pop(); } 56 } 57 58 signed main(){ 59 n=read(); m=read(); k=read(); 60 for(rin i=1;i<=n;i++) a[i]=read(); 61 for(rin i=1;i<=n;i++){ 62 sum=(p+sum-g[a[i]])%p; 63 g[a[i]]=(g[a[i]]+sum+1)%p; 64 sum=(sum+g[a[i]])%p; 65 lst[a[i]]=i; 66 } 67 for(int i=1;i<=k;i++) q.push(node(g[i],lst[i])); 68 init(); 69 while(m){ 70 if(m&1) f=mul(base,f); 71 base=mul(base,base); 72 m>>=1; 73 } 74 for(rin i=1;i<=k;i++) (ans+=f.s[i][1])%=p; 75 write(ans,'\n'); 76 return 0; 77 }
T3 omeed
暴力$75$,正解神仙数据结构,线段树上维护基础分的和与左端点$-1$处连击分推出右端点连击分与$\sum_{i=l}^r p_i(combo_{i-1}+1)$的系数。
太神仙了不知道如何讲。丢个代码爬了
$code:$
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 namespace IO{ 5 inline int read(){ 6 int x=0,f=1; char ch=getchar(); 7 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 8 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 9 return x*f; 10 } 11 inline void write(int x,char sp){ 12 char ch[20]; int len=0; 13 if(x<0){ putchar('-'); x=~x+1; } 14 do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x); 15 for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp); 16 } 17 } using namespace IO; 18 19 const int NN=5e5+5,mod=998244353; 20 int id,n,q,t,A,B,p[NN],combo,combos,basics,opt; 21 struct node{ int k,b,sum,ans,xi; }; 22 23 inline int inv(int x){ 24 int b=mod-2,res=1; 25 while(b){ 26 if(b&1) res=1ll*res*x%mod; 27 x=1ll*x*x%mod; 28 b>>=1; 29 } 30 return res; 31 } 32 33 namespace segment_tree{ 34 #define ld rt<<1 35 #define rd (rt<<1)|1 36 int k[NN<<2],b[NN<<2],sum[NN<<2],ans[NN<<2],xi[NN<<2],l[NN<<2],r[NN<<2]; 37 inline void pushup(int rt){ 38 sum[rt]=(1ll*sum[ld]+sum[rd])%mod; 39 k[rt]=1ll*k[ld]*k[rd]%mod; 40 b[rt]=(1ll*b[ld]*k[rd]%mod+b[rd])%mod; 41 xi[rt]=(1ll*xi[rd]*k[ld]%mod+xi[ld])%mod; 42 ans[rt]=(1ll*b[ld]*xi[rd]%mod+ans[ld]+ans[rd])%mod; 43 } 44 void build(int rt,int opl,int opr){ 45 l[rt]=opl; r[rt]=opr; 46 if(opl==opr){ 47 k[rt]=(p[opl]+t-1ll*p[opl]*t%mod+mod)%mod; 48 b[rt]=p[opl]; 49 xi[rt]=ans[rt]=sum[rt]=p[opl]; 50 return; 51 } 52 int mid=opl+opr>>1; 53 build(ld,opl,mid); build(rd,mid+1,opr); 54 pushup(rt); 55 } 56 void update(int rt,int pos){ 57 if(l[rt]==r[rt]){ 58 k[rt]=(p[pos]+t-1ll*p[pos]*t%mod+mod)%mod; 59 b[rt]=p[pos]; 60 xi[rt]=ans[rt]=sum[rt]=p[pos]; 61 return; 62 } 63 int mid=l[rt]+r[rt]>>1; 64 if(pos<=mid) update(ld,pos); 65 else update(rd,pos); 66 pushup(rt); 67 } 68 node query(int rt,int opl,int opr){ 69 if(l[rt]>=opl&&r[rt]<=opr) return (node){k[rt],b[rt],sum[rt],ans[rt],xi[rt]}; 70 int mid=l[rt]+r[rt]>>1; 71 node tmp1={0,0,0,0,0},tmp2={0,0,0,0,0},res; 72 if(opl<=mid) tmp1=query(ld,opl,opr); 73 if(opr>mid) tmp2=query(rd,opl,opr); 74 res.k=1ll*tmp1.k*tmp2.k%mod; 75 res.b=(1ll*tmp1.b*tmp2.k%mod+tmp2.b)%mod; 76 res.sum=(tmp1.sum+tmp2.sum)%mod; 77 res.ans=(1ll*tmp1.b*tmp2.xi%mod+tmp1.ans+tmp2.ans)%mod; 78 res.xi=(tmp1.xi+1ll*tmp2.xi*tmp1.k%mod)%mod; 79 return res; 80 } 81 } using namespace segment_tree; 82 83 signed main(){ 84 id=read(); 85 n=read(); q=read(); t=read(); t=1ll*t*inv(read())%mod; A=read()%mod; B=read()%mod; 86 for(int i=1;i<=n;i++) p[i]=read(), p[i]=1ll*p[i]*inv(read())%mod; 87 build(1,1,n); 88 while(q--){ 89 opt=read(); 90 if(opt==0){ 91 int x=read(),w=read(); w=1ll*w*inv(read())%mod; 92 p[x]=w; update(1,x); 93 } else{ 94 int ll=read(),rr=read(); 95 node tmp=query(1,ll,rr); 96 write((1ll*A*tmp.sum%mod+1ll*B*tmp.ans%mod)%mod,'\n'); 97 } 98 } 99 return 0; 100 }