2021.9.9考试总结[NOIP模拟50]
T1 第零题
神秘结论:从一个点满体力到另一个点的复活次数与倒过来相同。
于是预处理出每个点向上走第$2^i$个死亡点的位置,具体实现可以倍增或二分。
每次询问先从两个点同时向上倍增,都转到离$LCA$最近的死亡点上,然后判断,如果现在两点路径上权值大于$k$则答案加$1$。
$code:$


1 #include<bits/stdc++.h>
2 #define int long long
3 using namespace std;
4
5 namespace IO{
6 inline int read(){
7 char ch=getchar(); int x=0,f=1;
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<<4)+(1<<5); x/=10; }while(x);
16 for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
17 }
18 inline int max(int x,int y){ return x<y?y:x; }
19 inline int min(int x,int y){ return x<y?x:y; }
20 inline void swap(int &x,int &y){ x^=y^=x^=y; }
21 inline void chmax(int &x,int y){ x=x<y?y:x; }
22 inline void chmin(int &x,int y){ x=x<y?x:y; }
23 } using namespace IO;
24
25 const int NN=2e5+5;
26 int n,q,k,s,t,idx,to[NN<<1],nex[NN<<1],w[NN<<1],head[NN],det[NN][20],mi[20];
27 inline void add(int a,int b,int c){
28 to[++idx]=a; nex[idx]=head[b]; head[b]=idx; w[idx]=c;
29 to[++idx]=b; nex[idx]=head[a]; head[a]=idx; w[idx]=c;
30 }
31
32 namespace Tree_divide{
33 int cnt,fa[NN],dfn[NN],dep[NN],id[NN],top[NN],siz[NN],son[NN],pre[NN];
34 void dfs1(int s,int f){
35 dep[s]=dep[f]+1; siz[s]=1; fa[s]=f;
36 for(int i=head[s];i;i=nex[i]){
37 int v=to[i];
38 if(v==f) continue;
39 pre[v]=pre[s]+w[i];
40 dfs1(v,s);
41 siz[s]+=siz[v];
42 if(siz[v]>siz[son[s]]) son[s]=v;
43 }
44 }
45 void dfs2(int s,int t){
46 top[s]=t; dfn[s]=++cnt; id[cnt]=s;
47 if(!son[s]) return;
48 dfs2(son[s],t);
49 for(int i=head[s];i;i=nex[i]){
50 int v=to[i];
51 if(v!=fa[s]&&v!=son[s]) dfs2(v,v);
52 }
53 }
54 inline int LCA(int x,int y){
55 while(top[x]!=top[y])
56 if(dep[top[x]]>dep[top[y]]) x=fa[top[x]];
57 else y=fa[top[y]];
58 return dep[x]<dep[y]?x:y;
59 }
60 inline int get(int x){
61 int tmp=pre[x],l,r,res;
62 while(x&&tmp-pre[top[x]]<k) x=fa[top[x]];
63 if(!x) return 0;
64 r=dfn[x]; l=dfn[top[x]];
65 while(l<=r){
66 int mid=l+r>>1;
67 if(tmp-pre[id[mid]]>=k) l=mid+1, res=mid;
68 else r=mid-1;
69 }
70 return id[res];
71 }
72 void dfs3(int s){
73 det[s][0]=get(s);
74 for(int i=1;i<20;i++) det[s][i]=det[det[s][i-1]][i-1];
75 for(int i=head[s];i;i=nex[i])
76 if(to[i]!=fa[s]) dfs3(to[i]);
77 }
78 } using namespace Tree_divide;
79
80 signed main(){
81 n=read(); k=read(); mi[0]=1;
82 for(int i=1;i<20;i++) mi[i]=mi[i-1]*2;
83 for(int a,b,c,i=1;i<n;i++)
84 a=read(),b=read(),c=read(), add(a,b,c);
85 dfs1(1,0); dfs2(1,1); dfs3(1);
86 q=read();
87 while(q--){
88 s=read(); t=read();
89 int lca=LCA(s,t),ans=0;
90 for(int i=19;~i;i--){
91 if(dep[det[s][i]]>=dep[lca]) s=det[s][i], ans+=mi[i];
92 if(dep[det[t][i]]>=dep[lca]) t=det[t][i], ans+=mi[i];
93 }
94 if(pre[s]+pre[t]-2*pre[lca]>=k) ++ans;
95 write(ans,'\n');
96 }
97 return 0;
98 }
T1
T2 第负一题
分治,每次考虑过中点$mid$的区间对答案的贡献。
线性$DP$求出$L_0[j],L_1[j],R_0[j],R_1[j]$,分别表示左右区间$mid$或$mid+1$选或不选,向外选到$j$的最优策略。
合并时对左右端点$l,r$,贡献为$max(L_1[l]+R_0[r],L_0[l]+R_0[r],L_0[l]+R_1[r])$。
提出$L_0[l]+R_0[r]$,令$ld[l]=max(L_1[l]-L_0[l]),rd[r]=max(R_1[r]-R_0[r],0)$,贡献为$L_0[l]+R_0[r]+max(ld[l],rd[r])$。
考虑拆开贡献,对$ld$与$rd$的贡献,用单调指针计算即可。
$code:$


1 #include<bits/stdc++.h>
2 #define int long long
3 using namespace std;
4
5 namespace IO{
6 inline int read(){
7 char ch=getchar(); int x=0,f=1;
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<<4)+(1<<5); x/=10; }while(x);
16 for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
17 }
18 inline int max(int x,int y){ return x<y?y:x; }
19 inline int min(int x,int y){ return x<y?x:y; }
20 inline void swap(int &x,int &y){ x^=y^=x^=y; }
21 inline void chmax(int &x,int y){ x=x<y?y:x; }
22 inline void chmin(int &x,int y){ x=x<y?x:y; }
23 } using namespace IO;
24
25 const int NN=2e5+5,p=998244353;
26 int n,ans,a[NN],f[NN][2][2],L[NN][2],R[NN][2];
27 vector<int>ld,rd;
28
29 void solve(int l,int r){
30 if(l>=r) return (ans+=a[l])%=p,void();
31 int mid=l+r>>1,tl=0,tr=0,exl=mid-l+1,exr=r-mid;
32 solve(l,mid); solve(mid+1,r);
33 ld.clear(); rd.clear();
34 ld.push_back(a[mid]); rd.push_back(a[mid+1]);
35 for(int i=l;i<=r;i++)
36 f[i][0][0]=f[i][1][0]=f[i][0][1]=f[i][1][1]=0;
37 f[mid][1][1]=L[mid][1]=a[mid]; f[mid+1][1][1]=R[mid+1][1]=a[mid+1];
38 for(int i=mid-1;i>=l;i--){
39 f[i][1][0]=f[i+1][0][0]+a[i];
40 f[i][1][1]=f[i+1][0][1]+a[i];
41 f[i][0][0]=max(f[i+1][0][0],f[i+1][1][0]);
42 f[i][0][1]=max(f[i+1][0][1],f[i+1][1][1]);
43 L[i][0]=max(f[i][1][0],f[i][0][0]);
44 L[i][1]=max(f[i][1][1],f[i][0][1]);
45 ld.push_back(max(L[i][1]-L[i][0],0));
46 }
47 for(int i=mid+2;i<=r;i++){
48 f[i][1][0]=f[i-1][0][0]+a[i];
49 f[i][1][1]=f[i-1][0][1]+a[i];
50 f[i][0][0]=max(f[i-1][0][0],f[i-1][1][0]);
51 f[i][0][1]=max(f[i-1][0][1],f[i-1][1][1]);
52 R[i][0]=max(f[i][1][0],f[i][0][0]);
53 R[i][1]=max(f[i][1][1],f[i][0][1]);
54 rd.push_back(max(R[i][1]-R[i][0],0));
55 }
56 sort(ld.begin(),ld.end()); sort(rd.begin(),rd.end());
57 for(int i=l;i<=mid;i++) (ans+=L[i][0]*exr)%=p;
58 for(int i=mid+1;i<=r;i++) (ans+=R[i][0]*exl)%=p;
59 for(int i=0;i<ld.size();i++){
60 int now=ld[i];
61 while(tl<exr&&rd[tl]<=now) ++tl;
62 (ans+=tl*now)%=p;
63 }
64 for(int i=0;i<rd.size();i++){
65 int now=rd[i];
66 while(tr<exl&&ld[tr]<now) ++tr;
67 (ans+=tr*now)%=p;
68 }
69 }
70
71 signed main(){
72 n=read();
73 for(int i=1;i<=n;i++) a[i]=read();
74 solve(1,n);
75 write(ans,'\n');
76 return 0;
77 }
T2
T3 第负二题
标算不依赖随机性,但我太弱不会。
于是题目让我干啥我就干啥。
枚举行,每次用该行上下的左右端点更新该行左右端点,重复操作直到全是$0$。
因为数据随机所以可过。 UPD:被战神卡了。太强了
$code:$


1 #include<bits/stdc++.h>
2 #define mp make_pair
3 #define x first
4 #define y second
5 #define int unsigned long long
6
7 using namespace std;
8 typedef pair<int,int> pii;
9 namespace input{
10 int xorshift128p(int &A,int &B) {
11 int T=A,S=B;
12 A=S;
13 T^=T<<23;
14 T^=T>>17;
15 T^=S^(S>>26);
16 B=T;
17 return T+S;
18 }
19 void gen(int n,int L,int X,int Y,int A,int B,int l[],int r[]){
20 for (int i=1;i<=n;i++){
21 l[i]=xorshift128p(A,B)%L+X;
22 r[i]=xorshift128p(A,B)%L+Y;
23 if(l[i]>r[i]) swap(l[i],r[i]);
24 }
25 }
26 } using namespace input;
27
28 namespace IO{
29 inline int read(){
30 char ch=getchar(); int x=0;
31 while(ch<'0'||ch>'9'){ ch=getchar(); }
32 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
33 return x;
34 }
35 inline void write(int x,char sp){
36 char ch[20]; int len=0;
37 if(x<0){ putchar('-'); x=~x+1; }
38 do{ ch[len++]=x%10+(1<<4)+(1<<5); x/=10; }while(x);
39 for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
40 }
41 inline int max(int x,int y){ return x<y?y:x; }
42 inline int min(int x,int y){ return x<y?x:y; }
43 inline void swap(int &x,int &y){ x^=y^=x^=y; }
44 inline void chmax(int &x,int y){ x=x<y?y:x; }
45 inline void chmin(int &x,int y){ x=x<y?x:y; }
46 } using namespace IO;
47
48 const int NN=5e6+5,p=998244353,inf=0x3fffffff;
49 int n,ans,L,A,B,X,Y,tim,l[NN],r[NN],dis[NN],mi[NN],tl[NN],tr[NN];
50 queue<pii>q;
51 bool go;
52
53 signed main(){
54 n=read(); L=read(); X=read(); Y=read(); A=read(); B=read(); gen(n,L,X,Y,A,B,l,r);
55 mi[0]=go=1; l[0]=l[n+1]=inf; r[0]=r[n+1]=0;
56 for(int i=1;i<=n;i++) mi[i]=mi[i-1]*3%p;
57 while(go){
58 ++tim; go=0;
59 for(int i=1;i<=n;i++){
60 if(l[i]>r[i]) continue;
61 tl[i]=l[i]+1, tr[i]=r[i]-1;
62 chmax(tl[i],max(l[i-1],l[i+1]));
63 chmin(tr[i],min(r[i-1],r[i+1]));
64 }
65 for(int i=1;i<=n;i++){
66 if(l[i]>r[i]) continue;
67 l[i]=tl[i]; r[i]=tr[i];
68 if(l[i]>r[i]) dis[i]=tim;
69 else go=1;
70 }
71 }
72 for(int i=1;i<=n;i++) (ans+=dis[i]*mi[i-1]%p)%=p;
73 write(ans,'\n');
74 return 0;
75 }
T3假
再UPD:
整出了$O(n)$。
考虑答案的朴素意义:$f_i$成立,当且仅当在第$i$行有一个点,使所有$i$与该点的曼哈顿距离不超过$f_i-1$。
于是设$k=f_i-1$,当前行数为$i$,符合条件的点在第$y$列,则有:
$\begin{cases} y-[k-(i-j)]\geq l_j,y+[k-(i-j)]\leq r_j &j\in[i-k,i]\\ y-[k-(j-i)]\geq l_j,y+[k-(j-i)]\leq r_j &j\in[i.i+k] \end{cases}$
不难发现答案有单调性,$RMQ$加二分可以达到$O(nlog)$。
发现$|f_i-f_{i-1}|\leq 1$,于是在上一行答案确定的情况下不用二分,答案最多只有三种情况,$\textit{check}f_{i-1}$与$f_{i-1}+1$即可。
通过一顿加一减一发现区间右端点单调不减,左端点左移是$O(1)$级别的,因此维护单调队列,每次把左端点左边没考虑到的点考虑一下即可。
$code:$


1 #include<bits/stdc++.h>
2 #define mp make_pair
3 #define x first
4 #define y second
5
6 using namespace std;
7 typedef pair<int,int> pii;
8 namespace input{
9 typedef unsigned long long u64;
10 u64 xorshift128p(u64 &A, u64 &B) {
11 u64 T = A, S = B;
12 A = S;
13 T ^= T << 23;
14 T ^= T >> 17;
15 T ^= S ^ (S >> 26);
16 B = T;
17 return T + S;
18 }
19 void gen(int n, int L, int X, int Y, u64 A, u64 B, int l[], int r[]) {
20 for (int i = 1; i <= n; i ++) {
21 l[i] = xorshift128p(A, B) % L + X;
22 r[i] = xorshift128p(A, B) % L + Y;
23 if (l[i] > r[i]) swap(l[i], r[i]);
24 }
25 }
26 } using namespace input;
27
28 namespace IO{
29 inline int read(){
30 char ch=getchar(); int x=0;
31 while(ch<'0'||ch>'9'){ ch=getchar(); }
32 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
33 return x;
34 }
35 inline void write(int x,char sp){
36 char ch[20]; int len=0;
37 if(x<0){ putchar('-'); x=~x+1; }
38 do{ ch[len++]=x%10+(1<<4)+(1<<5); x/=10; }while(x);
39 for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
40 }
41 inline int max(int x,int y){ return x<y?y:x; }
42 inline int min(int x,int y){ return x<y?x:y; }
43 inline void swap(int &x,int &y){ x^=y^=x^=y; }
44 inline void chmax(int &x,int y){ x=x<y?y:x; }
45 inline void chmin(int &x,int y){ x=x<y?x:y; }
46 } using namespace IO;
47
48 const int NN=5e6+5,p=998244353,inf=0x3fffffff;
49 int n,ans,L,X,Y,f[NN],l[NN],r[NN],mi[NN];
50 int ql1[NN],ql2[NN],qr1[NN],qr2[NN],tl1,tl2,hl1,hl2,tr1,tr2,hr1,hr2,pre;
51 unsigned long long A,B;
52
53 inline bool check(int pos,int mid){
54 int now=mid-1,tmp,l1,l2,r1,r2;
55 for(int i=pre-1;i>=max(1,pos-now);--i) if(l[i]+i>l[ql1[hl1]]+ql1[hl1]) ql1[--hl1]=i;
56 for(int i=pre-1;i>=max(1,pos-now);--i) if(r[i]-i<r[qr1[hr1]]-qr1[hr1]) qr1[--hr1]=i;
57 pre=pos-now;
58 while(hl1<=tl1&&ql1[hl1]+now<pos) ++hl1;
59 while(hr1<=tr1&&qr1[hr1]+now<pos) ++hr1;
60 while(hl2<=tl2&&ql2[hl2] <pos) ++hl2;
61 while(hr2<=tr2&&qr2[hr2] <pos) ++hr2;
62 while(hl1<=tl1&&l[ql1[tl1]]+ql1[tl1]<=l[pos]+pos) --tl1;
63 while(hr1<=tr1&&r[qr1[tr1]]-qr1[tr1]>=r[pos]-pos) --tr1;
64 ql1[++tl1]=qr1[++tr1]=pos;
65 while(ql2[tl2]<pos+now){
66 tmp=ql2[tl2]+1;
67 while(hl2<=tl2&&l[ql2[tl2]]-ql2[tl2]<=l[tmp]-tmp) --tl2;
68 ql2[++tl2]=tmp;
69 }
70 while(qr2[tr2]<pos+now){
71 tmp=qr2[tr2]+1;
72 while(hr2<=tr2&&r[qr2[tr2]]+qr2[tr2]>=r[tmp]+tmp) --tr2;
73 qr2[++tr2]=tmp;
74 }
75 l1=l[ql1[hl1]]+ql1[hl1]+now-pos; r1=r[qr1[hr1]]-qr1[hr1]-now+pos;
76 l2=l[ql2[hl2]]-ql2[hl2]+now+pos; r2=r[qr2[hr2]]+qr2[hr2]-now-pos;
77 return max(l1,l2)>0&&max(l1,l2)<=min(r1,r2);
78 }
79
80 signed main(){
81 n=read(); L=read(); X=read(); Y=read(); cin>>A>>B; gen(n,L,X,Y,A,B,l,r);
82 mi[0]=f[1]=hl1=hl2=hr1=hr2=1;
83 ql1[++tl1]=qr1[++tr1]=ql2[++tl2]=qr2[++tr2]=1;
84 for(int i=1;i<=n;i++) mi[i]=1ll*mi[i-1]*3%p;
85 for(int i=2;i<=n;i++){
86 if(f[i-1] >0) if(check(i,f[i-1] )) f[i]=f[i-1];
87 else{ f[i]=f[i-1]-1; continue; }
88 if(f[i-1]+1>0) if(check(i,f[i-1]+1)) f[i]=f[i-1]+1;
89 }
90 for(int i=1;i<=n;i++) (ans+=1ll*f[i]*mi[i-1]%p)%=p;
91 write(ans,'\n');
92 return 0;
93 }
T3真
2021.9.9考试总结[NOIP模拟50]的更多相关文章
- 2021.9.17考试总结[NOIP模拟55]
有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...
- 2021.9.20考试总结[NOIP模拟57]
(换个编辑器代码就SB地不自动折叠了.. T1 2A 考察快读的写法. $code:$ T1 #include<bits/stdc++.h> #define scanf SCANF=sca ...
- 2021.9.13考试总结[NOIP模拟52]
T1 路径 考虑每一位的贡献,第$i$位每$2^i$个数会变一次,那么答案为$\sum_{i=1}^{log_2n} \frac{n}{2^i}$. $code:$ 1 #include<bit ...
- 2021.8.11考试总结[NOIP模拟36]
T1 Dove玩扑克 考场并查集加树状数组加桶期望$65pts$实际$80pts$,考后多开个数组记哪些数出现过,只扫出现过的数就切了.用$set$维护可以把被删没的数去掉,更快. $code:$ 1 ...
- 2021.7.29考试总结[NOIP模拟27]
T1 牛半仙的妹子图 做法挺多的,可以最小生成树或者最短路,复杂度O(cq),c是颜色数. 我考场上想到了原来做过的一道题影子,就用了并查集,把边权排序后一个个插入,记录权值的前缀和,复杂度mlogm ...
- 2021.7.15考试总结[NOIP模拟16]
ZJ模拟D2就是NB.. T1 Star Way To Heaven 谁能想到这竟是个最小生成树呢?(T1挂分100的高人JYF就在我身边 把上边界和下边界看成一个点和星星跑最小生成树,从上边界开始跑 ...
- 2021.10.15考试总结[NOIP模拟77]
\(n=40\)考虑\(meet \;in \;the \;middle\) 某个元素有关的量只有一个时考虑转化为树上问题 对暴力有自信,相信数据有梯度 没了 UPD:写了个略说人话的. T1 最大或 ...
- 2021.10.9考试总结[NOIP模拟72]
T1出了个大阴间题 状压\(DP\),记当前状态的代价和与方案数.状态\(\Theta(2^nn)\),转移\(\Theta(n)\). 发现每个状态的最大值只会是所选集合的\(max\)或加一.于是 ...
- 2021.9.28考试总结[NOIP模拟64]
T1 三元组 发现确定\(b,c\)的情况下,\(a\)的值域是连续的.确定\(b\)后\(a+b\)的取值是\([1+b,b+b]\).树状数组维护对每个\(b\)可行的\(c\). 注意取模后取值 ...
随机推荐
- CSS导航菜单(二级菜单)
index.html <div class="nav"> <ul> <li> <a href="#">Java& ...
- AWVS13批量添加目标脚本
# -*-coding:utf-8-*- # @Author:malphite.tang import json import requests from queue import Queue req ...
- Python增强下git那长长的指令
场景 现如今有点规模的公司都使用GitFlow模式进行分支管理.虽然插件给我们带来了非常大的方便,但切换分支.找分支.起分支还是那么的麻烦 需求 在社会主次国家,每个生活在底层的劳动人民,他们默默的工 ...
- AES加密基本原理图解
AES加密 Fright-Moch整理 AES简介 高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的).对 ...
- 离散化模板题 II ——重复元素离散化后的数字不相同
离散化模板题 II --重复元素离散化后的数字不相同 题目描述 现有数列A1, A2, ⋯, An,数列中可能有重复元素. 现在要求输出该数列的离散化数列,重复元素离散化后的数字不相同. 输入 第一行 ...
- 动态规划精讲(一)A单串
单串 单串 dp[i] 线性动态规划最简单的一类问题,输入是一个串,状态一般定义为 dp[i] := 考虑[0..i]上,原问题的解,其中 i 位置的处理,根据不同的问题,主要有两种方式: 第一种是 ...
- 深入学习Composer原理(一)
Composer作为PHP的包管理工具,为PHPer们提供了丰富的类库,并且让PHP重焕新生,避免被时代淘汰的悲剧.可以说,Composer和PHP7是现在PHP开发者的标配,如果你还没用过Compo ...
- TP5模型开启事务
和Db开启事务类似,Db是静态方法 $userObj = new UserModel(); $userObj->startTrans(); try { $userObj->data($da ...
- [转载]用redis实现跨服务器session
地址:http://blog.chinaunix.net/uid-11121450-id-3284875.html 这个月我们新开发了一个项目,由于使用到了4台机器做web,使用dns做负载均衡, 上 ...
- 鸿蒙内核源码分析(VFS篇) | 文件系统和谐共处的基础 | 百篇博客分析OpenHarmony源码 | v68.01
子曰:"质胜文则野,文胜质则史.文质彬彬,然后君子." <论语>:雍也篇 百篇博客系列篇.本篇为: v68.xx 鸿蒙内核源码分析(VFS篇) | 文件系统和谐共处的基 ...