7-12 子序列(2023郑州轻工业大学校赛

Posted Demoo.

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了7-12 子序列(2023郑州轻工业大学校赛相关的知识,希望对你有一定的参考价值。

题意:

有一个长度为n的子序列,第i个数为a[i]
求不超过三对位置的元素相等的子序列的个数

思路:

对于每个数,我们先存他有几个位置

然后我们再遍历每种数:

设数x的不同位置有y个

dp[i]表示所选的序列恰好有i对相等的数的序列的个数

dp[0]表示所选序列中恰好有0对相同的数的序列的个数,那么我们在之前的所有的序列之后选上x这个数或者不选x这个数之后,所选的序列依旧是有0对相同的数,有因为x这个数有y种位置,所以我们有y+1种选法,即:

dp[0]=dp[0]*(y+1)

dp[1]表示所选序列中恰好有1对相同的数的序列个数
那么由两部分组成:
1.在之前序列中相同的数为0对的序列的基础上,再选一对相同的x(在y个位置里选两个),即dp[0] * C y 2 C_y^2 Cy2
2.在之前序列中相同的数为1对的序列的基础上,再选一个x,或者不选x,即dp[1] *(y+1)

dp[2]表示所选序列中恰好有两对相同的数的序列的个数
那么由两部分组成:
1.在之前相同数的对数为1的序列的基础上,再选一对相同的x(在y个位置里选两个),即dp[1] * C y 2 C_y^2 Cy2
2.在之前序列中相同的数为两对的序列的基础上,再选一个x,或者不选,即dp[2] *(y+1)

dp[3]表示所选序列中恰好有三对相同的数的序列的个数
那么由三部分组成:
1.在之前相同数的对数为0的基础上选三对相同的x(在y个位置中选三个),即dp[0] * C y 3 C_y^3 Cy3;
2.在之前相同数对数为2的序列的基础上选一对相同的x(在y个位置里选两个),即dp[2] * C y 2 C_y^2 Cy2
3.在之前相同数对数为3的序列的基础上选一个x或者不选x,即dp[3] *(y+1)

#include<bits/stdc++.h>
#include<vector>
#define int long long
using namespace std;
const int N=2e5+10;
const int mod=998244353;
typedef long long ll;
int n,m;
int a[N];
ll dp[N][6];
int f[N],fi[N];
int ksm(int a,int b)
	int res=1%mod;
	while(b)
		if(b&1)res=res*a%mod;
		a=a*a%mod;
		b>>=1;
	
	return res;

void init()
	f[0]=fi[0]=1;
	for(int i=1;i<N;i++)
		f[i]=(f[i-1]*i)%mod;
		fi[i]=(fi[i-1]*ksm(i,mod-2))%mod;
	

signed main()
	scanf("%lld",&n);
	init();
	map<int,int> mp;
	vector<int> op;
	op.push_back(0);
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]);
		mp[a[i]]++;
		op.push_back(a[i]);
	
	sort(op.begin(),op.end());
	op.erase(unique(op.begin(),op.end()),op.end());
	dp[0][0]=1;
	for(int i=1;i<op.size();i++)
		int y=mp[op[i]];
		dp[i][3]=dp[i-1][3]%mod*(y+1)%mod;
		if(y>=2)
			dp[i][3]=(dp[i][3]+dp[i-1][2]%mod*(f[y]*fi[2]%mod*fi[y-2]%mod)%mod)%mod;
		
		if(y>=3)
			dp[i][3]=(dp[i][3]+dp[i-1][0]%mod*(f[y]*fi[3]%mod*fi[y-3]%mod)%mod)%mod;
		
		dp[i][2]=(dp[i-1][2]%mod*(y+1))%mod;
		if(y>=2)
			dp[i][2]=(dp[i][2]%mod+dp[i-1][1]*(f[y]*fi[2]%mod*fi[y-2]%mod)%mod)%mod;
		
		dp[i][1]=(dp[i-1][1]%mod*(y+1)%mod)%mod;
		if(y>=2)
			dp[i][1]=(dp[i][1]%mod+dp[i-1][0]*(f[y]*fi[2]%mod*fi[y-2]%mod)%mod)%mod;
		
		dp[i][0]=dp[i-1][0]*(y+1)%mod;
	
	ll ans=0;
	int len=op.size();
	for(int i=0;i<=3;i++)
		ans=(ans%mod+dp[len-1][i]%mod)%mod;
	
	cout<<ans-1;//减掉一个空字符
	
	return 0;

7-8 what‘s 莫比乌斯最大值(2023郑州轻工业大学校赛

题意:

有n个问题和闲聊

问题的格式是’what’s + S 问题 S_问题 S问题

闲聊的格式是 S 问题 S_问题 S问题+ S 回答 S_回答 S回答 S 问题 S_问题 S问题的长度>=0

对于每个 S 回答 S_回答 S回答 ,只能回答在这句话之前提问的问题

那么求最多能回答几个不同的问题

思路:

对于每个回答,他的每个前缀都可能是一个出现过的问题

那么我们对于一个回答,让他贪心的回答出现过的前缀最长的问题

因为对于一个回答,如果他的长度长,可以回答长度长的问题和长度短的问题,如果他的长度短的话就只能回答长度短的问题,所以我们优先让他回答没有回答过的长度最长的问题

用umap来记录一个问题是否出现过,以及是否被回答过。

注意:

加了ios::sync_with_stdio(false)就不能用getchar(),需要用cin.get()

对于map的每次询问都是插入,如果对于每出现过的map,需要先判断是否出现过载判断值,可以节省时间防止tle

#include<bits/stdc++.h>
using namespace std;
const int N=4e6+10;
int idx,n;

int main()
	ios::sync_with_stdio(false);
	cin.tie(),cout.tie();
	cin>>n;
	cin.get();//加了ios不能用getchar
	unordered_map<string,int> chuxian;//记录是否被回答过,如果等于0就是没有
	unordered_map<string,int> huida;
	int con=0;
	for(int i=1;i<=n;i++)
		string s;
		cin>>s;
		if(s=="what's")
			cin>>s;
			chuxian[s]=1;
		else
			string op;
			int id=-1;
			string ans;
			for(int i=0;i<s.size();i++)
				op+=s[i];
				if(chuxian.count(op)&&chuxian[op]==1&&huida.count(op)==0)
					id=i;
					ans=op;
				
			
			if(id!=-1)
				huida[ans]=1;
				con++;
			
		
	
	cout<<con;
	return 0;


以上是关于7-12 子序列(2023郑州轻工业大学校赛的主要内容,如果未能解决你的问题,请参考以下文章

20170416郑州市轻工业学院ACM校赛

LitCTF-Writeup-BlackManba

河南工业大学2017校赛题解

2017浙江工业大学-校赛决赛 画图游戏

河南工业大学校赛 C题.魔法宝石

2017浙江工业大学-校赛决赛 猜猜谁是我