【补题计划】CSP-S 2021

【CSP-S 2021】补题记录

T1 【CSP-S 2021】廊桥分配

这明显就不是普通的签到题啊(记得当时我刚学OI 只会数组和for循环搞出来15pts

现在看题解发现还是很简单滴,就是用PQ模拟一下再维护一下前缀和然后枚举一下

但是当年在考场上好像因为长得就像一个贪心模板然后坑了不少人

AC code

点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<algorithm>
#define pii pair<int,int>

using namespace std;

const int maxn=1e5+5;

inline int read()
{
	int w=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch=='-')
		{
			f=-1;
		}
		ch=getchar();
	}
	while(ch>='0' && ch<='9')
	{
		w=(w<<3)+(w<<1)+(ch^48);
		ch=getchar();
	}
	return w*f;
}

int n,m1,m2,ans;

int res_in[maxn];

int res_out[maxn];

struct flight
{
	int come;
	int leave;
}in[maxn],out[maxn];

bool cmp(flight x,flight y)
{
	return x.come<y.come;
}

void calc(flight* t,int m,int* res)
{
	priority_queue <int,vector<int>,greater<int> > wait;
	priority_queue <pii,vector<pii>,greater<pii> > have;
	
	for(int i=1;i<=n;i++)
	{
		wait.push(i);
	}
	
	for(int i=1;i<=m;i++)
	{
		while(!have.empty() && have.top().first<=t[i].come)
		{
			wait.push(have.top().second);
			have.pop();
		}
		if(wait.empty()) continue;
		res[wait.top()]++;
		have.push(make_pair(t[i].leave,wait.top()));
		wait.pop();
	}
	for(int i=1;i<=n;i++)
	{
		res[i]=res[i-1]+res[i];
	}
}

int main()
{
	n=read(),m1=read(),m2=read();
	
	for(int i=1;i<=m1;i++)
	{
		in[i].come=read();
		in[i].leave=read();
	}
	
	for(int i=1;i<=m2;i++)
	{
		out[i].come=read();
		out[i].leave=read();
	}
	
	sort(in+1,in+m1+1,cmp);
	
	sort(out+1,out+m2+1,cmp);
	
	calc(in,m1,res_in);
	
	calc(out,m2,res_out);
	
	for(int i=0;i<=n;i++)
	{
		ans=max(ans,res_in[i]+res_out[n-i]);
	}
	
	cout<<ans;
	
	return 0;
}

T2 【CSP-S 2021】括号序列

这题好SB。。。。。

大家应该都能一眼鉴定位区间DP吧

但是转移属实是麻烦,第三位表示这个字符串的形状

dp[l][r][0] : ********(我真没骂人,打的就是星号)

dp[l][r][1] :(****)

dp[l][r][2] :()****

dp[l][r][3] :(里边只要合法就行)

dp[l][r][4] : ****()

dp[l][r][5] : **** () ****

然后就是要注意一下最后一种包含了第一种,第四种包含了第二种

然后就是暴力的转移一下就行力

最后因为题目要求是两边都是()所以第四种状态即为ans (dp[1][n][3])

AC code

点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#define int long long

using namespace std;

const int maxn=510;

const int mod=1e9+7;	

int n,k;

char str[maxn];

int dp[maxn][maxn][6];

bool cmp(int l,int r)
{
	return ((str[l]=='(' || str[l]=='?') && (str[r]==')' || str[r]=='?'));
}

signed main()
{
	scanf("%lld%lld",&n,&k); cin>>(str+1);
	
	for(int i=1;i<=n;i++)
	{
		dp[i][i-1][0]=1; //初始化是为了方便转移 
	}
	
	for(int len=1;len<=n;len++)
	{
		for(int l=1;l<=n-len+1;l++)
		{
			int r=l+len-1;
			if(len<=k) dp[l][r][0]=dp[l][r-1][0]*(str[r]=='?' || str[r]=='*');  //从这行开始就很一目了然 
			if(len>=2)
			{
				if(cmp(l,r)) dp[l][r][1]=(dp[l+1][r-1][0]+dp[l+1][r-1][2]+dp[l+1][r-1][3]+dp[l+1][r-1][4])%mod;
				for(int i=l;i<r;i++)
				{
					dp[l][r][2]=(dp[l][r][2]+dp[l][i][3]*dp[i+1][r][0])%mod; 
					dp[l][r][3]=(dp[l][r][3]+(dp[l][i][2]+dp[l][i][3])*dp[i+1][r][1])%mod;
					dp[l][r][4]=(dp[l][r][4]+(dp[l][i][4]+dp[l][i][5])*dp[i+1][r][1])%mod;
					dp[l][r][5]=(dp[l][r][5]+dp[l][i][4]*dp[i+1][r][0])%mod;
				}
			}
			dp[l][r][5]=(dp[l][r][5]+dp[l][r][0])%mod;
			dp[l][r][3]=(dp[l][r][3]+dp[l][r][1])%mod;
		}
	}
	
	cout<<dp[1][n][3]; 
	
	return 0;
}

T3 【CSP-S 2021】回文

借鉴了@Eafoo的思路:先针对第一个出去的元素进行讨论

先讨论从左出去的情况(从右出去也同理),因为这样字典序肯定比先从右出去小

我们先找到第一个出去的元素的同素异形体(bushi),然后就把序列分成了两段

用两个双端队列维护,数组ans1表示第一个这样的字符出去的方向,ans2表示和他一样的那个字符

那么假设这个元素是i个出去的,另一个就是倒数第i个,所以ans2要倒序输出

剩下的就是按回文还有字典序的顺序什么的模拟判断了(突然感觉压行也挺不错滴)

AC code

点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<deque>
#include<algorithm>

using namespace std;

const int maxn=1e6+5;

inline int read()
{
	int w=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9')
	{
		w=(w<<3)+(w<<1)+(ch^48);
		ch=getchar();
	}
	return w*f;
}

int t,n,cnt_1,cnt_2;

int a[maxn];

char ans1[maxn],ans2[maxn];

deque <int> l,r;

bool check()
{
	while(!l.empty() || !r.empty())
	{
		bool L=!l.empty(),R=!r.empty();
		bool LL=l.size()>1,RR=r.size()>1;
		char lc,rc;
		if(LL && l.front()==l.back()) l.pop_front(),l.pop_back(),lc='L',rc='L';
		else if(L && R && l.front()==r.back()) l.pop_front(),r.pop_back(),lc='L',rc='R';
		else if(L && R && r.front()==l.back()) r.pop_front(),l.pop_back(),lc='R',rc='L';
		else if(RR && r.front()==r.back()) r.pop_front(),r.pop_back(),lc='R',rc='R';
		else break;
		ans1[++cnt_1]=lc,ans2[++cnt_2]=rc;
	}
	if(l.empty() && r.empty())
	{
		for(int i=1;i<=cnt_1;i++)
		{
			cout<<ans1[i];
		}
		for(int i=cnt_2;i>=1;i--)
		{
			cout<<ans2[i];
		}
		cout<<endl;
		return true;
	}
	return false;
}

void work()
{
	n=2*read();int p;
	l.clear(),r.clear();
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=2;i<=n;i++) if(a[i]==a[1]){ p=i; break; }	
	for(int i=2;i<p;i++) l.push_back(a[i]);
	for(int i=n;i>=p+1;i--) r.push_back(a[i]);
	ans1[cnt_1=1]='L',ans2[cnt_2=1]='L';
	if(check())	return ;
	l.clear(),r.clear();
	for(int i=1;i<n;i++) if(a[i]==a[n]){ p=i; break; };
	for(int i=1;i<p;i++) l.push_back(a[i]);
	for(int i=n-1;i>=p+1;i--) r.push_back(a[i]);
	ans1[cnt_1=1]='R',ans2[cnt_2=1]='L';
	if(check()) return;
	cout<<-1<<endl;
}

int main()
{
	t=read();while(t--) work();
	return 0;
}

T4 【CSP-S 2021】交通规划

很明显,这题不可做,考场上骗骗分(k<=2)然后自求多福吧

posted @ 2022-09-25 20:30  NinT_W  阅读(40)  评论(0编辑  收藏  举报