3020年牛客NOIP集训营
只拿了20分,T1 签到多测没清空+条件想到了忘写了;T2 50tps暴力因为队列访问空炸了;T4暴力没写完
其实凭实力可以拿到100+50+10+40分,很高了,但是就是不在状态
调整状态!踏实做题!力求高分!
[双向链表]T2:给出n种球和n个柱形容器,有3种操作,【1】x,y,z:把x个y球放进z号柱子【2】x,y:把x个球从顶部拿出y号柱子【3】x,y:把x柱子里的球顺次放入y。对于【2】操作,输出最后一个拿出的球的编号。(n<=5e5)
考场
首先是不可抑制的暴力思维:直接vector模拟,加了2个优化,一个是合并同类,一个是不关心未询问的柱子,但是没什么用。
然后想到链表维护操作,但是不知道【3】操作怎么转换链表方向(nxt/pre?),放弃了
正解
链表的加入类似建图的过程,维护head和2个方向,不用关注2个方向的指针种类,只要朝着走向走就可以(now=son[0]-->go[1]/ now=son[1]-->go[0]),对于最棘手的【3】,可以直接把head的x和y拼接,使heady指向tailx
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define rint register int
#define ll long long
#define ull unsigned long long
#define chu printf
inline ll re()
{
ll x=0,h=1;char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')h=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*h;
}
const int N=3e5+100;
struct buf
{
int cor,cnt,ch[2];
}e[N];
int h[N],t[N],n,m,tot;
int main()
{
// freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
freopen("color.in","r",stdin);
freopen("color.out","w",stdout);
n=re(),m=re();
for(rint i=1;i<=m;++i)
{
char s[6];
scanf("%s",s+1);
int x=re(),y=re(),z;
if(s[3]=='s')
{
z=re();
e[++tot]=(buf){y,x,h[z],0};
if(h[z])
{
e[h[z]].ch[0]?(e[h[z]].ch[1]=tot):(e[h[z]].ch[0]=tot);
}
else t[z]=tot;
h[z]=tot;
}
else if(s[3]=='p')
{
while(e[h[y]].cnt<x)
{
x-=e[h[y]].cnt;//删除y
int lch=e[h[y]].ch[0]|e[h[y]].ch[1];
(e[lch].ch[0]==h[y])?(e[lch].ch[0]=0):(e[lch].ch[1]=0);
h[y]=lch;
}
e[h[y]].cnt-=x;
chu("%d\n",e[h[y]].cor);
}
else
{
if(!h[x])continue;
if(h[y])
{
e[h[y]].ch[0]?e[h[y]].ch[1]=h[x]:e[h[y]].ch[0]=h[x];
e[h[x]].ch[0]?e[h[x]].ch[1]=h[y]:e[h[x]].ch[0]=h[y];
}
else t[y]=h[x];
h[y]=t[x];
h[x]=t[x]=0;
}
}
return 0;
}
/*
3 5
push 1 1 1
push 1 2 1
push 2 3 2
put 1 2
pop 2 2
*/
[字符串匹配+局部处理思想]T4:定义偶数串是length是偶数,且满足结构AA的串,给出一个长度是n的偶数串,你可以进行若干次操作使得最终偶数串长度>=m,要求每次变换新增串最少,给出q次询问[l,r],询问区间的十进制数字%998244353的结果。(n<=1e5,m<=1e18)
考场
10pts
枚举相同后缀
40tps
kmp线性更新nxt,预处理串的[l,r]表示
正解
定义u=vv,w是v的前缀,满足v-w是v的前缀。
如果\(len_w|len_v\),偶串形态:\(vwwwwwwww\)
否则定义\(v0=w,v1=v,vi=v_{i-1}+v_{i-2}\),一直构造下去一定合法,
所以预处理每个v,直到长度>=m(最多logn个),询问只需维护前缀答案拼凑,维护时因为fib数列可拼凑,所以最后剩下的项<=length,直接散块累加,发i西安对于【1】情况这么干不影响答案。
\(O(q*logn+logn^2)\)
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define rint register int
#define ll long long
#define ull unsigned long long
#define chu printf
inline ll re()
{
ll x=0,h=1;char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')h=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*h;
}
const int N=120;
const int mod=998244353;//mod
ll h[100000+100];int nxt[100000+100];
ll l[120],f[120],rt[120];int n,q,mx;
ll m;
char s[100000+100];
inline ll qpow(ll a,ll b)
{
ll c=1;
while(b)
{
if(b&1)c=c*a%mod;
a=a*a%mod;
b>>=1;
}
return c;
}
inline ll get(ll go)
{
ll sg=0;ll ans=0;
for(rint i=mx;i>=0;--i)
{
if(sg+l[i]<=go)
{
sg+=l[i];
ans=(ans*rt[i]%mod+f[i])%mod;
}
}
ans=(ans*qpow(10,go-sg)%mod+h[go-sg])%mod;
return ans;
}
inline void solve()
{
scanf("%s",s+1);
m=re(),q=re();
n=strlen(s+1)/2;
for(rint i=2;i<=n;++i)
{
int j=nxt[i-1];
while(j&&s[j+1]!=s[i])j=nxt[j];
if(s[j+1]==s[i])nxt[i]=j+1;
else nxt[i]=0;
}
for(rint i=1;i<=n;++i)h[i]=(h[i-1]*10ll%mod+s[i]-'0');
l[0]=n-nxt[n],f[0]=h[l[0]];rt[0]=qpow(10,l[0]);//意识到不对劲
l[1]=n,f[1]=h[l[1]],rt[1]=qpow(10,l[1]);
for(rint i=2;i<=100;++i)
{
l[i]=l[i-1]+l[i-2];
f[i]=(1ll*f[i-1]*rt[i-2]%mod+f[i-2])%mod;
rt[i]=qpow(10,l[i]);
if(l[i]>=m){mx=i;break;}
}
for(rint i=1;i<=q;++i)
{
ll let=re(),ret=re();
ll ans=get(ret)-get(let-1)*qpow(10,ret-let+1)%mod+mod;
ans%=mod;
chu("%lld\n",ans);
}
}
int main()
{
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
freopen("even.in","r",stdin);
freopen("even.out","w",stdout);
int T=re();
while(T--)solve();
return 0;
}
/*
*/