Loading

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);
}
posted @ 2021-10-22 07:23  AaMuXiiiiii  阅读(35)  评论(0编辑  收藏  举报