测试「2020牛客NOIP赛前集训营-提高组(第四场)」
考试时间在周末,估计没几个人认真考,于是混了个rk13。
T1
枚举 \(V\) 的位置,判断前后是否合法。
\(\text{Code}:\)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long lxl;
const int maxn=1e5+5;
template <typename T>
inline void read(T &x)
{
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
x*=f;
}
int n;
char s[maxn];
int w[26];
bool chk[2][maxn];
int main()
{
#ifndef ONLINE_JUDGE
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
#endif
int T;read(T);
while(T--)
{
for(int i=0;i<26;++i) read(w[i]);
scanf(" %s",s+1);
n=strlen(s+1);
if(!((w[s[n]-'a']>>1)&1)) {puts("No");continue;}
for(int i=1;i<=n;++i)
{
chk[0][i]=chk[0][i-1];
int c=s[i]-'a';
if(w[c]==4) chk[0][i]=true;
}
for(int i=n;i>=1;--i)
{
chk[1][i]=chk[1][i+1];
int c=s[i]-'a';
if(w[c]==4) chk[1][i]=true;
}
bool flag=false;
for(int i=2;i<n;++i)
{
int c=s[i]-'a';
if(((w[c]>>2)&1)&&!chk[0][i-1]&&!chk[1][i+1]&&((w[s[i-1]-'a']>>1)&1))
{
flag=true;
break;
}
}
puts(flag?"Yes":"No");
}
return 0;
}
T2
考试的时候没多想,看到数据范围 \(2\cdot10^5\) 直接上平衡树模拟了。
\(\text{Code}:\)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define Rint register int
#define INF 0x3f3f3f3f
using namespace std;
typedef long long lxl;
const int maxn=3e5+5;
template <typename T>
inline void read(T &x)
{
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
x*=f;
}
int n,m;
namespace Treap
{
int tot,pool[maxn],top;
int ch[maxn][2];
lxl siz[maxn],cnt[maxn];
int val[maxn],rnd[maxn];
bool rev[maxn];
inline int new_node()
{
int p=top?pool[top--]:++tot;
ch[p][0]=ch[p][1]=0;
siz[p]=cnt[p]=0;
val[p]=rnd[p]=0;
rev[p]=false;
return p;
}
inline void reverse(int p)
{
swap(ch[p][0],ch[p][1]);
rev[p]^=1;
}
inline void push_down(int p)
{
if(!rev[p]) return;
reverse(ch[p][0]);
reverse(ch[p][1]);
rev[p]=0;
}
inline void update(int p)
{
siz[p]=siz[ch[p][0]]+siz[ch[p][1]]+cnt[p];
}
void split_rnk(int p,int k,int &x,int &y,int &z)
{
if(!p) return x=y=z=0,void();
push_down(p);
if(siz[ch[p][0]]>=k)
{
z=p;
split_rnk(ch[p][0],k,x,y,ch[p][0]);
}
else if(siz[ch[p][0]]+cnt[p]<k)
{
x=p;
split_rnk(ch[p][1],k-siz[ch[p][0]]-cnt[p],ch[p][1],y,z);
}
else
{
x=ch[p][0],y=p,z=ch[p][1];
ch[p][0]=ch[p][1]=0;
}
update(p);
}
int merge(int a,int b)
{
if(!a||!b) return a|b;
push_down(a),push_down(b);
if(rnd[a]<rnd[b])
{
ch[a][1]=merge(ch[a][1],b);
update(a);
return a;
}
else
{
ch[b][0]=merge(a,ch[b][0]);
update(b);
return b;
}
}
inline int new_node(int s,int c)
{
if(!s) return 0;
int p=new_node();
siz[p]=cnt[p]=s;
val[p]=c;
rnd[p]=rand();
return p;
}
inline void erase(int &p)
{
if(!p) return;
erase(ch[p][0]);
erase(ch[p][1]);
pool[++top]=p;
p=0;
}
// inline void print(int p)
// {
// if(!p) return;
// push_down(p);
// print(ch[p][0]);
// for(int i=1;i<=cnt[p];++i)
// printf("%d ",val[p]);
// print(ch[p][1]);
// }
}
int rt[maxn];
int main()
{
#ifndef ONLINE_JUDGE
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
#endif
read(n),read(m);
char opt[5];
int x,y,z;
while(m--)
{
scanf(" %s",opt);
read(x),read(y);
if(opt[2]=='s')
{
read(z);
rt[z]=Treap::merge(Treap::new_node(x,y),rt[z]);
}
else if(opt[2]=='p')
{
int a,b,c;
Treap::split_rnk(rt[y],x,a,b,c);
rt[y]=Treap::merge(Treap::new_node(Treap::siz[a]+Treap::cnt[b]-x,Treap::val[b]),c);
printf("%d\n",Treap::val[b]);
Treap::erase(a);
Treap::erase(b);
}
else
{
Treap::reverse(rt[x]);
rt[y]=Treap::merge(rt[x],rt[y]);
rt[x]=0;
}
// puts("---");
// for(int i=1;i<=n;++i)
// Treap::print(rt[i]),puts("");
// puts("---");
}
return 0;
}
T3
令 \(g(n)=fib(n)^2\) ,则由数理基础可以发现:\(g(n)=2\times g(n-1)+2\times g(n-2)-g(n-3)\) 。
于是 \(g(n)\) 可以矩阵递推:
\[\begin{bmatrix}
g(n)\\
g(n-1)\\
g(n-2)\\
\end{bmatrix}
=
\begin{bmatrix}
2&2&-1\\
1&0&0\\
0&1&0
\end{bmatrix}
\times
\begin{bmatrix}
g(n-1)\\
g(n-2)\\
g(n-3)
\end{bmatrix}
\]
令
\[A=
\begin{bmatrix}
2&2&-1\\
1&0&0\\
0&1&0
\end{bmatrix},
G_n=
\begin{bmatrix}
g(n)\\
g(n-1)\\
g(n-2)\\
\end{bmatrix}
\]
则有 \(G_n=A^nG_0\) 。
考虑如何通过矩阵递推求出 \(f_S\) ,将 \(f_S\) 向量化为 \(F_S\) 。由 \(f_S=\sum_{T\subseteq S}g_{\sum_{x\in T}x}\) ,得到:
\[F_{S}=\sum_{T\subseteq S}G_{\sum_{x\in T}x}
\]
则:
\[\begin{aligned}
F_{S\cup\{a\}}&=F_{S}+\sum_{T\subseteq S}G_{a+\sum_{x\in T}x}\\
&=F_S+\sum_{T\subseteq S}A_aG_{\sum_{x\in T}x}\\
&=F_S+A^aF_S\\
&=(I+A^a)F_S
\end{aligned}
\]
由定义可知:\(F_0=G_0\) 。令 \(B_a=I+A^a\) ,则:
\[\begin{aligned}
S&=\{a_1,a_2,a_3,\cdots,a_n\}\\
F_S&=\prod_{i=1}^nB_{a_i}G_0
\end{aligned}
\]
于是用线段树维护区间 \([l,r]\) 的 \(\sum_{i=l}^r\sum_{j=l}^r\prod_{k=i}^jB_{a_k}\) 即可。
\(\text{Code}:\)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define Rint register int
#define INF 0x3f3f3f3f
using namespace std;
typedef long long lxl;
const int maxn=1e5+5;
const lxl mod=998244353;
template <typename T>
inline void read(T &x)
{
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
x*=f;
}
struct Matrix
{
int A[5][5],N,M;
Matrix(int N,int M):N(N),M(M){memset(A,0,sizeof(A));}
Matrix(){}
inline Matrix operator + (const Matrix &T)const
{
Matrix res=*this;
for(int i=1;i<=N;++i)
for(int j=1;j<=M;++j)
(res.A[i][j]+=T.A[i][j])%=mod;
return res;
}
inline Matrix operator * (const Matrix &T)const
{
Matrix res=Matrix(N,T.M);
for(int i=1;i<=N;++i)
for(int k=1;k<=M;++k)
for(int j=1;j<=T.M;++j)
(res.A[i][j]+=1ll*A[i][k]*T.A[k][j]%mod)%=mod;
return res;
}
inline void print()
{
for(int i=1;i<=N;++i,puts(""))
for(int j=1;j<=M;++j)
printf("%d ",A[i][j]);
puts("");
}
}I,A[maxn],G;
struct node
{
int l,r;
Matrix sum,ans,lsum,rsum;
node(int l,int r,Matrix sum=I,Matrix ans=I,Matrix lsum=I,Matrix rsum=I)
:l(l),r(r),sum(sum),ans(ans),lsum(lsum),rsum(rsum){}
node(){}
inline node operator + (const node &T)const
{
node res(l,T.r);
res.sum=sum*T.sum;
res.ans=ans+T.ans+rsum*T.lsum;
res.lsum=lsum+sum*T.lsum;
res.rsum=rsum*T.sum+T.rsum;
return res;
}
};
int n,q,a[maxn];
namespace Segment_Tree
{
node tree[maxn<<2];
#define ls (p<<1)
#define rs (p<<1|1)
inline void set(int p,Matrix d)
{
tree[p].sum=tree[p].ans=tree[p].lsum=tree[p].rsum=d;
}
void build(int p,int l,int r)
{
tree[p]=node(l,r);
if(l==r) return set(p,I+A[a[l]]),void();
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
tree[p]=tree[ls]+tree[rs];
}
void modify(int p,int ps,int d)
{
int l=tree[p].l,r=tree[p].r;
if(l==r) return set(p,I+A[d]),void();
int mid=(l+r)>>1;
if(ps<=mid) modify(ls,ps,d);
else modify(rs,ps,d);
tree[p]=tree[ls]+tree[rs];
}
node query(int p,int L,int R)
{
int l=tree[p].l,r=tree[p].r;
if(L<=l&&r<=R) return tree[p];
int mid=(l+r)>>1;
if(R<=mid) return query(ls,L,R);
else if(L>mid) return query(rs,L,R);
else return query(ls,L,R)+query(rs,L,R);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("C.in","r",stdin);
freopen("C.out","w",stdout);
#endif
read(n),read(q);
for(int i=1;i<=n;++i) read(a[i]);
I=Matrix(3,3);I.A[1][1]=I.A[2][2]=I.A[3][3]=1;
A[1]=Matrix(3,3);
A[1].A[1][1]=A[1].A[1][2]=2;A[1].A[1][3]=mod-1;
A[1].A[2][1]=A[1].A[3][2]=1;
for(int i=2;i<=1e5;++i)
A[i]=A[i-1]*A[1];
G=Matrix(3,1);G.A[1][1]=0;G.A[2][1]=G.A[3][1]=1;
Segment_Tree::build(1,1,n);
int opt,x,y;
while(q--)
{
read(opt),read(x),read(y);
if(opt==1) Segment_Tree::modify(1,x,y);
else
{
node res=Segment_Tree::query(1,x,y);
// res.ans.print();
printf("%d\n",(res.ans*G).A[1][1]);
}
}
return 0;
}