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 }
T1

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 }
T2

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 }
T3

 

posted @ 2021-08-25 07:34  keen_z  阅读(41)  评论(0编辑  收藏  举报