2020 牛客 NOIP 赛前集训营-提高组 (第四场)

T1

我第一想到的是dp的状态机模型
d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k],i为当前扫到第i位,j表示该位的状态,分为三种:0为A,1为N,2为V,k表示是否用过V,1为是,0为否
状态转移见代码。
直接输出 d p [ n ] [ 1 ] [ 1 ] dp[n][1][1] dp[n][1][1]即是答案

#include<bits/stdc++.h>
using namespace std;

const int M = 100100;
int a[30], T, len;
char c[M];
int dp[M][3][2];

//状态转移方程
void A(int i){
	dp[i+1][0][0] = dp[i][0][0] | dp[i][1][0];
	dp[i+1][0][1] = dp[i][0][1] | dp[i][1][1] | dp[i][2][1];
}
void N(int i){
	dp[i+1][1][0] = dp[i][1][0] | dp[i][0][0];
	dp[i+1][1][1] = dp[i][1][1] | dp[i][0][1] | dp[i][2][1];
}
void V(int i){
	if(!i) return;
	dp[i+1][2][1] = dp[i][1][0];
}

int main()
{
	freopen("language.in", "r", stdin);
	freopen("language.out", "w", stdout);
	scanf("%d", &T);
	while(T--)
	{
		memset(dp, 0, sizeof dp);
		dp[0][0][0] = 1, dp[0][1][0] = 1;
		
		for(int i=0 ; i<26 ; i++)
			scanf("%d", &a[i]);
		memset(c, 0, sizeof c);
		scanf("%s", &c);
		for(int i=0 ; c[i] ; i++)
		{
			int t = c[i]-'a';
			if(a[t]==1) A(i);
			if(a[t]==2) N(i);
			if(a[t]==3) A(i), N(i);
			if(a[t]==4) V(i);
			if(a[t]==5) A(i), V(i);
			if(a[t]==6) N(i), V(i);
			if(a[t]==7) A(i), N(i), V(i);
			len = i;
		}
		
		if(dp[len+1][1][1]) puts("Yes");
		else puts("No");
	}
	

	
	return 0;
}

T2

暴力可以拿到前几个点的分,主要讲讲正解。
每个位置用双向链表顺序记录放的球的个数和颜色。对于询问 1,往位置 z 的链表上加一个结点(𝑥, 𝑦)。对于询问 2,从位置 z 的链表头取,如果当前需要取𝒙个而当前结点拥有的球。𝑥′ < 𝑥个,则整个结点删掉,𝑥更新为𝑥 − 𝑥′。如果𝑥′ ≥ 𝑥,那么输出当前的颜色𝑦′,并且把 𝑥′更新为𝑥′ − 𝑥。对于询问 3,把位置𝑢的链表头直接拼接到位置𝑣的链表头上,位置𝑢的链表尾作为位置𝑣新的链表头。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 301001;
struct node {
 int c,num,ch[2];
} buf[maxn];
int n,m,h[maxn],t[maxn],tot;
int main() {
 	scanf("%d%d",&n,&m);
 	for (int i=0;i<m;i++) {
 	char op[6];
 	int x,y,z;
 	scanf("%s%d%d",op,&x,&y);
	 if (op[2]=='s') {
 		scanf("%d",&z);
 		buf[++tot]=(node){y,x,h[z],0};
		 if (h[z])
			buf[h[z]].ch[0]?(buf[h[z]].ch[1]=tot):(buf[h[z]].ch[0]=tot);
		 else t[z]=tot;
		 h[z]=tot;
 	} 
 	else if (op[2]=='p')
 	{
		while (buf[h[y]].num<x) {
		 x-=buf[h[y]].num;
		 int lch=buf[h[y]].ch[0]|buf[h[y]].ch[1];
		 if (lch)
			buf[lch].ch[0]==h[y]?(buf[lch].ch[0]=0):(buf[lch].ch[1]=0);
 			h[y]=lch;
 		}
 		buf[h[y]].num-=x;
		printf("%d\n",buf[h[y]].c);
	} else {
 		if (!h[x]) continue;
 		if (h[y]) {
			buf[h[y]].ch[0]?(buf[h[y]].ch[1]=h[x]):(buf[h[y]].ch[0]=h[x]);
			buf[h[x]].ch[0]?(buf[h[x]].ch[1]=h[y]):(buf[h[x]].ch[0]=h[y]);
 	} else 
 		t[y]=h[x];
 	
		 h[y]=t[x];
 		h[x]=t[x]=0;
 		}
	 }
 	return 0;
}

T4

我们根据121121进行拓展,发现每次拓展的位数为4、6、10、16,符合斐波拉子数列,所以我们可以用斐波拉子数列优化。
更系统的说法如下,来源:牛客竞赛
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
由于苯人太菜了,没有写出100的代码,所以我直接搬运了牛客的代码。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值