加载中…

返回上一页

NOIP模拟1

下发文件

语言

只需要有至少两个 N 和只有一个 V 组成,且两个 N 要在 V 左边和最右边.

记得判一下是否有多个 V,还有就是如果有一个必选V,其左边必须是一个 N. 因为这个挂了 60.

点击查看代码
#include<bits/stdc++.h>
#define ll int
#define rg register
#define rll rg ll
#define maxn 100001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10|'0'); }
ll t,n,tp[27],cnt[8];
char s[maxn];
bool fl;
inline void findv()
{
	if(cnt[4]) { cnt[4]--; if(cnt[4]) fl=1; cnt[4]++; return; } if(cnt[5]) { cnt[5]--; return; }
	if(cnt[7]) { cnt[7]--; return; } if(cnt[6]) { cnt[6]--; return; } fl=1;
}
inline void findn() { if(cnt[2]+cnt[3]+cnt[6]+cnt[7]<2) fl=1; }
inline void chkn() { if(tp[s[n]^'`']==1||tp[s[n]^'`']==4||tp[s[n]^'`']==5) fl=1; }
int main()
{
	freopen("language.in","r",stdin); freopen("language.out","w",stdout);
	t=read(); while(t--)
	{
		fl=0; for(rll i=1;i<=26;i++) tp[i]=read(); scanf("%s",s+1); n=strlen(s+1);
		memset(cnt,0,sizeof(cnt)); for(rll i=1;i<=n;i++) cnt[tp[s[i]^'`']]++;
		findv();findn();chkn(); if(fl) { puts("No");continue; } fl=1;
		for(rll i=2;i<n;i++)
			if((tp[s[i]^'`']==4||tp[s[i]^'`']==5||tp[s[i]^'`']==6||tp[s[i]^'`']==7)
				&&(tp[s[i-1]^'`']==2||tp[s[i-1]^'`']==3||tp[s[i-1]^'`']==6||tp[s[i-1]^'`']==7)&&((cnt[4]&&tp[s[i]^'`']==4)||(!cnt[4])))
			{ fl=0;break; }
		puts(fl?"No":"Yes");
	}
	return 0;
}

色球

STLbasic_string 可以水到 50 分.

正解是搞一个双向链表,每一次在它上面加点、删点,全部取出的情况就把它反向连接,所以记录两个 head 即可.

点击查看代码
#include<bits/stdc++.h>
#define ll int
#define rg register
#define rll rg ll
#define maxn 200001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10|'0'); }
struct node { ll col,num,nxt,pre; }e[maxn<<1];
ll n,m,x,y,z,head[maxn],ls[maxn],tot;
char s[11];
int main()
{
	freopen("color.in","r",stdin); freopen("color.out","w",stdout);
	// x=1;y=2;g[x].push_back({ 1,2 });g[x].push_back({ 2,3 });g[y].push_back({ 24,44 });g[x].push_back({ 5,50 });
	// reverse_copy(g[x].begin(),g[x].end(),g[y].begin());
	// for(rll i=0;i<g[y].size();i++) cout<<g[y][i].first<<' '<<g[y][i].second<<endl;
	n=read();m=read(); while(m--)
	{
		scanf("%s",s); switch(s[2])
		{
		case 's':// push
			x=read();y=read();z=read(); e[++tot]={ y,x,head[z],0 };
			if(head[z]) e[head[z]].nxt?e[head[z]].pre=tot:e[head[z]].nxt=tot;
			else ls[z]=tot; head[z]=tot; break;
		case 'p':// pop
			x=read();y=read();
			while(e[head[y]].num<x)
			{
				x-=e[head[y]].num; rll t=e[head[y]].nxt|e[head[y]].pre;
				if(t) e[t].nxt==head[y]?e[t].nxt=0:e[t].pre=0; head[y]=t;
			}
			e[head[y]].num-=x; write(e[head[y]].col);putn; break;
		case 't':// put
			x=read();y=read();if(!head[x])continue;
			if(head[y])
			{
				e[head[y]].nxt?(e[head[y]].pre=head[x]):(e[head[y]].nxt=head[x]);
				e[head[x]].nxt?(e[head[x]].pre=head[y]):(e[head[x]].nxt=head[y]);
			}
			else ls[y]=head[x]; head[y]=ls[x];head[x]=ls[x]=0;
			break;
		}
		// for(rll i=1;i<=3;i++) { write(i);putn; for(rll j=0;j<g[i].size();j++) write(g[i][j].second),put_,write(g[i][j].first),putn; }
	}
	return 0;
}

斐波

线段树优化矩阵快速幂.

首先,复习一下斐波那契矩阵:

需要求一个斐波那契数的平方,那么有下面这个式子:

f2(i) = [f(i - 1) + f(i - 2)]2 = f2(i - 1) + 2f(i - 1)f(i - 2) + f2(i - 2).

为了方便把它搞成矩阵,两边平方好说,中间的 2 倍把它化一下就是下面这个式子:

2f(i)f(i - 1) = 2[f(i - 1) + f(i - 2)]f(i - 1) = 2f2(i - 1) + 2f(i - 1)f(i - 2).

那么矩阵乘法式子就有了:

.

当一个数加入一个新的集合时,它会将两个集合原来的元素复制并加入其中每个元素相乘的结果.

那么就有了 (a + 1)(b + 1) = a + b + ab + 1.

这个 1 转化到矩阵上来就是:

.

这不单位矩阵嘛?

有了这些,要求所有这些的总和,那就使用线段树来维护. 整体就是一个单点改、区间查,不说.

pushup 的时候,需要稍微改一下废话.

记录一下一段区间(a)内的答案,这里设为 cheng(a). 设 I 为单位矩阵,显然,cheng(a) = fib(a) + I , cheng(a + b) = cheng(a)cheng(b).

a 的前缀答案为 pre(a),后缀答案为 nxt(a). 手推一下不难知道,pre(a + b) = pre(a) + cheng(a) × pre(b).

懒得画图了,推一下应该不难了解

nxt(a) 的求法也一样,反过来 nxt(a + b) = cheng(b) × nxt(a) + nxt(b).

设区间答案为 ans(a),把总的答案拼起来,ans(a + b) = ans(a) + ans(b) + nxt(a) × pre(b).

点击查看代码
#include<bits/stdc++.h>
#define ll int
#define rg register
#define rll rg ll
#define maxn 100001
#define mod 998244353
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10|'0'); }
struct node
{
	ll a[4][4]; node() { memset(a,0,sizeof(a)); }
	inline friend node operator+(rg node a,rg node b)
	{
		for(rll i=1;i<=3;i++) for(rll j=1;j<=3;j++) (a.a[i][j]+=b.a[i][j])%=mod; return a;
	}
	inline friend node operator*(rg node a,rg node b)
	{
		rg node c;
		for(rll i=1;i<=3;i++) for(rll j=1;j<=3;j++) for(rll k=1;k<=3;k++)
			(c.a[i][j]+=(long long)a.a[i][k]*b.a[k][j]%mod)%=mod;
		return c;
	}
	inline friend void operator+=(rg node& a,rg node b) { a=a+b; }
	inline friend void operator*=(rg node& a,rg node b) { a=a*b; }
}mul,jz1,fib[maxn];
struct tree
{
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
	node cheng,pre,nxt,ans;
	inline friend tree operator+(rg tree a,rg tree b)
	{
		rg tree c; c.cheng=a.cheng*b.cheng;c.pre=a.pre+a.cheng*b.pre;
		c.nxt=b.cheng*a.nxt+b.nxt;c.ans=a.ans+b.ans+a.nxt*b.pre; return c;
	}
	inline friend void operator+=(rg tree& a,rg tree b) { a=a+b; }
}t[maxn<<2];
ll n,q,x,y;
ll a[maxn];
#define pushup(rt) t[rt].cheng=t[ls(rt)].cheng*t[rs(rt)].cheng,\
t[rt].pre=t[ls(rt)].pre+t[ls(rt)].cheng*t[rs(rt)].pre,\
t[rt].nxt=t[rs(rt)].cheng*t[ls(rt)].nxt+t[rs(rt)].nxt,\
t[rt].ans=t[ls(rt)].ans+t[rs(rt)].ans+t[ls(rt)].nxt*t[rs(rt)].pre
inline void build(rll rt,rll l,rll r)
{
	if(l==r) { t[rt].cheng=t[rt].pre=t[rt].nxt=t[rt].ans=fib[a[l]]+jz1; return; }
	rll mid=(l+r)>>1; build(ls(rt),l,mid);build(rs(rt),mid+1,r); pushup(rt);
}
inline void upd(rll rt,rll l,rll r,rll pos,rll v)
{
	if(l==r) { t[rt].cheng=t[rt].pre=t[rt].nxt=t[rt].ans=fib[v]+jz1; return; } rll mid=(l+r)>>1;
	if(pos<=mid) upd(ls(rt),l,mid,pos,v); else upd(rs(rt),mid+1,r,pos,v); pushup(rt);
}
inline tree query(rll rt,rll l,rll r,rll x,rll y)
{
	if(x<=l&&r<=y) return t[rt]; rll mid=(l+r)>>1;
	if(x<=mid&&y>mid) return query(ls(rt),l,mid,x,y)+query(rs(rt),mid+1,r,x,y);
	else if(x<=mid) return query(ls(rt),l,mid,x,y); else if(y>mid) return query(rs(rt),mid+1,r,x,y);
}
int main()
{
	freopen("fib.in","r",stdin); freopen("fib.out","w",stdout);
	// 第一行三个数分别是:𝑓𝑖𝑏²(i+1)、𝑓𝑖𝑏²(i)、2𝑓𝑖𝑏(i+1)𝑓𝑖𝑏(i)
	// i=0 𝑓𝑖𝑏(i)=0
	// 1 0 0
	// 0 1 0
	// 0 0 1
	// i=1 𝑓𝑖𝑏(i)=1
	// 1 1 2
	// 1 0 0
	// 1 0 1
	// i=2 𝑓𝑖𝑏(i)=1
	// 4 1 4
	// 1 1 2
	// 2 1 3
	// i=3 𝑓𝑖𝑏(i)=2
	// 9 4 12
	// 4 1 4
	// 6 2 7
	// ……
	mul.a[1][1]=mul.a[1][2]=mul.a[2][1]=mul.a[3][1]=mul.a[3][3]=1;mul.a[1][3]=2;
	jz1.a[1][1]=jz1.a[2][2]=jz1.a[3][3]=1; fib[0]=jz1; for(rll i=1;i<maxn;i++) fib[i]=fib[i-1]*mul;
	// for(rll i=1;i<=3;i++) { for(rll j=1;j<=3;j++) { for(rll k=1;k<=3;k++) cout<<fib[i].a[j][k]<<' ';cout<<endl; } cout<<endl; }
	n=read();q=read(); for(rll i=1;i<=n;i++) a[i]=read(); build(1,1,n); while(q--) switch(read())
	{
	case 1:x=read();y=read();upd(1,1,n,x,y);break;
	case 2:x=read();y=read();write(query(1,1,n,x,y).ans.a[1][2]/*所以上面就解释了这里为什么是第一行第二列*/);putn;break;
	}
	return 0;
}

偶数

先咕着,大致知道是什么意思了,以后有时间再写(虽然这是我为开脱自己的借口

主要就是两种情况,先求一下周期,然后设两个串分别为 v , wwv 的前缀. 那么只需要维护这两个串的长度和值即可. 发现这玩意其实就是一个斐波那契.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 1000001
#define mod 998244353
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10|'0'); }
ll t,len,n,q,mx,l,r,nx[maxn],fib[maxn],num[maxn],f[maxn];
char s[maxn];
inline ll ksm(rll a,rll b) { rll ans=1;a%=mod; for(rll i=b;i;i>>=1) { if(i&1) (ans*=a)%=mod; (a*=a)%=mod; } return ans; }
inline ll solve(rll x)
{
	rll sum=0,ans=0; for(rll i=mx;~i;i--) if(sum+fib[i]<=x) ans=(ans*ksm(10,fib[i])%mod+f[i])%mod,sum+=fib[i];// ,fprintf(stderr,"%lld %lld\n",ans,sum);
	// fprintf(stderr,"%lld %lld %lld\n",ans,x,sum);
	return (ans*ksm(10,x-sum)%mod+num[x-sum])%mod;
}
int main()
{
	freopen("even.in","r",stdin); freopen("even.out","w",stdout);
	t=read();while(t--)
	{
		scanf("%s",s);len=(ll)strlen(s)>>1;n=read();q=read(); nx[0]=-1;
		for(rll i=0,j=-1;i<len;i++,j++) { while((~j)&&(s[i]^s[j])) j=nx[j]; nx[i+1]=j+1; }
		for(rll i=1;i<=len;i++) num[i]=((num[i-1]<<3)+(num[i-1]<<1)+(s[i-1]^'0'))%mod;
		fib[0]=len-nx[len];fib[1]=len;f[0]=num[fib[0]],f[1]=num[fib[1]]; mx=1;
		for(rll i=2;i<100;i++)
		{
			fib[i]=fib[i-1]+fib[i-2];f[i]=(f[i-1]*ksm(10,fib[i-2])%mod+f[i-2])%mod;
			fprintf(stderr,"fib[%lld]=%lld\n",i,fib[i]);
			if(fib[i]>=n) { mx=i; break; }
		}
		// putn;
		while(q--) l=read(),r=read(),write((solve(r)-solve(l-1)*ksm(10,r-l+1)%mod+mod)%mod),putn;
	}
	return 0;
}
posted @ 2022-11-02 19:42  1Liu  阅读(38)  评论(0编辑  收藏  举报