noip模拟81
A. 语言
乱写就行.
A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
#define ll long long
#define lf double
#define ull unsigned ll
#define lbt(x) ((x)&(-(x)))
#define mp make_pair
#define lb lower_bound
#define ub upper_bound
#define Fill(x,y) memset(x,y,sizeof(x))
#define Copy(x,y) memcpy(x,y,sizeof(x))
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
inline ll read(){
ll w=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) w=(w<<1)+(w<<3)+(ch^48),ch=getchar();
return cit?w:(-w);
}
} using namespace BSS;
const ll S=1e5+21;
char ch[S];
ll m,n,A,N,V;
ll r[30],c[S],val[S];
auto Work=[]()->void{
ll flag=0;
for(ll i=1;i<=26;i++) r[i]=read();
scanf("%s",ch+1),n=strlen(ch+1);
for(ll i=1;i<=n;i++){
c[i]=ch[i]-'a'+1,val[i]=r[c[i]];
flag|=((val[i]&V)>0);
}
if(val[1]==V or (!(val[n]&N))) flag=0;
if(!flag) { puts("No"); return ; }
flag=0;
for(ll i=1;i<=n;i++) if(val[i]==V) flag++;
if(flag>1) { puts("No"); return ; }
flag=0;
for(ll i=1;i<=n;i++) { if(val[i]==V) flag=i; break; }
if(flag){
if(val[flag-1]&N) { puts("Yes"); return; }
else { puts("No"); return ; }
}
for(ll i=2;i<n;i++){
if((val[i]&V) and (val[i-1]&N)) { puts("Yes"); return ; }
}
puts("No"); return ;
};
signed main(){
File(language);
A=1,N=2,V=4;
for(int Ts=read();Ts;Ts--) Work();
exit(0);
}
B. 色球
学习了双向链表.
B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
#define ll long long
#define lf double
#define ull unsigned ll
#define lbt(x) ((x)&(-(x)))
#define mp make_pair
#define lb lower_bound
#define ub upper_bound
#define Fill(x,y) memset(x,y,sizeof(x))
#define Copy(x,y) memcpy(x,y,sizeof(x))
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
inline ll read(){
ll w=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) w=(w<<1)+(w<<3)+(ch^48),ch=getchar();
return cit?w:(-w);
}
} using namespace BSS;
const ll N=2e5+21;
ll m,n,ops,tot;
ll tail[N],head[N];
struct I { ll col,cnt; ll con[2]; } p[N<<2];
inline void unit(ll &x,ll y){
p[x].con[0] ? p[x].con[1]=y : p[x].con[0]=y;
p[y].con[0] ? p[y].con[1]=x : p[y].con[0]=x;
}
signed main(){
File(color);
n=read(); char opt[15]; ll x,y,z,u,v,ci;
for(int Ts=read();Ts;Ts--){
scanf("%s",opt+1);
if(opt[3]=='s'){
p[++tot].cnt=read(),p[tot].col=read(),z=read();
if(head[z]) unit(head[z],tot);
else tail[z]=tot;
head[z]=tot;
}
if(opt[3]=='p'){
x=read(),z=read();
while(p[ci=head[z]].cnt<x){
x-=p[ci].cnt;
if(y=(p[ci].con[0]|p[ci].con[1]))
p[y].con[0]==ci ? p[y].con[0]=0 : p[y].con[1]=0;
head[z]=y;
}
p[head[z]].cnt-=x,printf("%lld\n",p[head[z]].col);
}
if(opt[3]=='t'){
u=read(),v=read();
if(!head[u]) continue;
if(ci=head[v]) unit(ci,head[u]);
else tail[v]=head[u];
head[v]=tail[u],head[u]=0,tail[u]=0;
}
}
exit(0);
}
C. 斐波
线段树上维护矩阵,可以直接维护结果矩阵,也可以维护系数矩阵.
我们发现这个题目很套娃,所以很自然地应该想到要简化问题,一步一步进行.
考虑如何迅速地求出斐波那契第 \(x\) 项,大概矩阵应该很好想到.
而斐波第 \(x\) 项的平方显然也是满足递推求解的,所以同样可以选择矩阵.
然后想办法求出 \(f(S)\),发现很具有组合意义.(乘法分配律角度上好像也可理解)..
首先我们考虑如果给出了一个集合 \(S\) 和集合里面每个数的值 \(a_i\),求出 \(\sum\limits_{T\subseteq S}\prod\limits_{a_i\in T} a_i\).
其实就是每个数之间的不同组合,于是可以选择求和 \(\prod\limits_i (a_i+1)\).
类比过来,就可以对 \(fib\) 进行同样的处理操作.
现在考虑如何处理 \(\sum\limits_l\sum\limits_r\),其实同样使用矩阵进行拆开就可以.
后面的请参考 \(Yubai\) 的博客,这里就不再给出了.
C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
#define ll long long
#define lf double
#define ull unsigned ll
#define pb push_back
#define mp make_pair
#define lb lower_bound
#define ub upper_bound
#define lbt(x) ((x)&(-(x)))
#define Fill(x,y) memset(x,y,sizeof(x))
#define Copy(x,y) memcpy(x,y,sizeof(x))
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
auto read=[]()->ll{
ll w=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return cit?w:(-w);
};
} using namespace BSS;
#define ls (x<<1)
#define rs (x<<1|1)
const ll N=1e5+21,mod=998244353;
ll m,n,ops;
ll val[N];
struct Mat{
ll w[4][4];
inline friend Mat operator *(Mat a,Mat b){
Mat c;
for(ll i=1;i<=3;i++){
for(ll j=1;j<=3;j++){
c.w[i][j]=0;
for(ll k=1;k<=3;k++)
c.w[i][j]=(c.w[i][j]+a.w[i][k]*b.w[k][j]%mod);
}
}
return c;
}
inline friend Mat operator +(Mat a, Mat b){
for(ll i=1;i<=3;i++){
for(ll j=1;j<=3;j++)
a.w[i][j]=(a.w[i][j]+b.w[i][j])%mod;
}
return a;
}
inline void Put(){
for(ll i=1;i<=3;i++){
for(ll j=1;j<=3;j++) cout<<w[i][j]<<' ';
puts("");
}
puts("");
}
}I,P,fib[N];
struct II { Mat mul,pre,suf,res; } tr[N<<2];
auto pushup=[](II &x,II l,II r)->void{
x.mul=l.mul*r.mul,x.res=l.res+r.res+l.suf*r.pre;
x.pre=l.pre+l.mul*r.pre,x.suf=r.suf+l.suf*r.mul;
};
void update(ll x,ll l,ll r,ll pos){
if(l==r){
assert(l==pos),tr[x].mul=tr[x].pre=tr[x].suf=tr[x].res=fib[val[l]]+I;
return void();
}
ll mid=(l+r)>>1;
(pos<=mid ? update(ls,l,mid,pos) : update(rs,mid+1,r,pos));
pushup(tr[x],tr[ls],tr[rs]);
}
void build(ll x,ll l,ll r){
if(l==r) return tr[x].mul=tr[x].pre=tr[x].suf=tr[x].res=fib[val[l]]+I,void();
ll mid=(l+r)>>1; build(ls,l,mid),build(rs,mid+1,r); pushup(tr[x],tr[ls],tr[rs]);
}
II query(ll x,ll l,ll r,ll ql,ll qr){
if(l>=ql and r<=qr) return tr[x];
ll mid=(l+r)>>1,flag=0; II ans;
if(ql<=mid) ans=query(ls,l,mid,ql,qr),flag=1;
if(qr>mid){
if(flag) pushup(ans,ans,query(rs,mid+1,r,ql,qr));
else ans=query(rs,mid+1,r,ql,qr);
}
return ans;
}
signed main(){
File(fib);
n=read(),ops=read(); ll l,r,x,y,z,opt; II ans;
for(ll i=1;i<=3;i++) P.w[1][i]=1,I.w[i][i]=1;
P.w[1][1]=P.w[2][1]=P.w[3][3]=1,P.w[3][1]=2,fib[0]=I;
for(ll i=1;i<=1e5;i++) fib[i]=fib[i-1]*P;
for(ll i=1;i<=n;i++) val[i]=read();
build(1,1,n);
while(ops--){
if(read()&1){
x=read(),val[x]=read(),update(1,1,n,x);
}
else{
l=read(),r=read(),ans=query(1,1,n,l,r);
printf("%lld\n",ans.res.w[1][2]);
}
}
exit(0);
}
D. 偶数
\(Border\) 理论学完了结果还是不会做题..
目前感觉字符串要么就是这种题,要么就是 \(Hash\)、\(Kmp\) 和 \(AC\) 自动机一类的匹配类问题.
首先发现这个题目给出的数据范围很大,很难不想到要简化为 \(log\) 级别的复杂度.
于是应该果断找规律的,字符串里的 \(border\) 和周期感觉是最有意思的,这个题同样需要灵活运用这些东西.
打表发现字符串变化长度的变化符合一个要么是固定增长,要么是类似于斐波的形式增长.
果不其然,确实是需要考虑这两种情况,于是分别计算为什么会是这两种形式,和什么情况对应哪一种形式.
题解里面给出的证明依旧是那么几个理论来回用,其中 \(WPL\) ( 弯破烂 )理论好像用的特别多.
关于题解里的一个证明:
证明: \(w\) 是 \(v\) 的最短周期,且 \(len(w)\) 不是 \(len(v)\) 的因子,则 \(vw\) 的最短的周期是 \(v\).
假设 \(x\) 为 \(vw\) 的最短周期,且 \(len(x)<len(v)\).
因为 \(len(x)<len(v)\),所以 \(x\) 显然也是 \(v\) 的周期,另外 \(w\) 是 \(v\) 的最短周期,所以可以根据 \(w\) 和 \(x\) 进行讨论.
如果 \(gcd(len(x),len(w))==w\),那么可以写为 \(len(x)=k*len(w)\).
如果 \(k==1\),即 \(x==w\),显然不可能成立.
如果 \(k>1\),那么 \(w\) 同样为 \(x\) 的周期,周期的周期同样是周期,与 \(x\) 是最短周期矛盾.
如果 \(gcd(len(x),len(w))\neq w\),那么 \(gcd(len(x),len(w))\) 同样是 \(v\) 的周期且长度要小于 \(len(w)\),与已知不符,所以矛盾.
综合以上几种情况,不可能有长度比 \(v\) 更小的周期,证毕.
不过这种题对于现在的自己,靠自己推出来还是有难度,应该多去思考.
最后想再写一下这个题在自己如果研究 \(200\) 年可能研究出来的流程:
打表 -> 发现两种形式 -> 先推理简单的形式,感觉可以直接做 -> 推理困难的形式,发现有规律可以做 -> 发现规律同样适用于简单的形式 -> 于是可以归结为同一种写法 -> 调了 \(100\) 年的题 -> 考试结束也没做出来.
D_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
#define ll long long
#define lf double
#define ull unsigned ll
#define pb push_back
#define mp make_pair
#define lb lower_bound
#define ub upper_bound
#define lbt(x) ((x)&(-(x)))
#define Fill(x,y) memset(x,y,sizeof(x))
#define Copy(x,y) memcpy(x,y,sizeof(x))
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
auto read=[]()->ll{
ll w=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return cit?w:(-w);
};
} using namespace BSS;
const ll N=1e5+21,mod=998244353;
char ch[N];
ll m,n,z,ops,ans;
ll f[N],g[N],val[N],len[N],nxt[N];
auto ksm=[](ll a,ll b,ll c,ll w=1)->ll{
for(a%=c,b%=(c-1);b;b>>=1,a=a*a%c) if(b&1) w=w*a%c;
return w%c;
};
auto calc=[](ll x)->ll{
ll res=0;
for(ll i=z;i and x;i--){
if(len[i]<=x){
res=(res*ksm(10,len[i],mod)%mod+f[i])%mod;
x-=len[i];
}
}
res=(res*ksm(10,x,mod)%mod+g[x])%mod;
return res%mod;
};
auto Work=[]()->void{
scanf("%s",ch+1),n=strlen(ch+1);
m=read(),ops=read(); ll l,r,x;
for(ll i=1;i<=n;i++){
val[i]=ch[i]-'0',len[i]=0,f[i]=0,nxt[i]=0;
g[i]=(g[i-1]*10%mod+val[i])%mod;
}
for(ll i=2,j=0;i<=n;i++){
while(j and (val[i]^val[j+1])) j=nxt[j];
j+=(val[i]==val[j+1]),nxt[i]=j;
}
len[1]=(n>>1)-nxt[n>>1],len[2]=n>>1,f[1]=g[len[1]],f[2]=g[len[2]];
for(ll i=3;;i++){
len[i]=len[i-1]+len[i-2];
f[i]=(f[i-1]*ksm(10,len[i-2],mod)%mod+f[i-2])%mod;
if(len[i]>=m) { z=i; break; }
}
len[z+1]=1e18;
while(ops--){
l=read(),r=read();
ans=(calc(r)-calc(l-1)*ksm(10,r-l+1,mod)%mod+mod)%mod;
printf("%lld\n",ans);
}
};
signed main(){
File(even);
for(int Ts=read();Ts;Ts--) Work();
exit(0);
}