“蔚来杯“2022牛客暑期多校训练营9补题

A  Car Show

题意

NIO王国有n城和m车系。根据调查,在第i个城市,Ti风格的汽车是最受欢迎的。现在NIO王国要举办车展,负责人想选择一个整数区间[l,r](1≤l≤r≤n)让指数在这个区间的城市联合举办车展。为了体现汽车的多样性,每种款式都应该在主办城市最受欢迎的款式中至少出现一次。确定满足上述约束的整数区间数。即给定一个长为n的包含1,2,...,m的序列,求有多少区间[L,R]包含所有1,2,...,m

思路

最开始将左端点设为1,在输入t[i]的同时,统计数字t[i]的个数,和不同的数字一共出现多少个(不需要考虑顺序和大小,直接判断新输入的数字的原个数是否为0,若为0则此是新数字,种类数加一),当种类数等于m时表明在此时的左右端点之间,所有种类的数字都至少出现过一次,在左端点不变的情况下,右端点可选择此时输入位置到末尾的任一位置,随后考虑此时位置不变时,向右移动左端点是否满足所有种类数字都至少出现过一次,当使左端点数字的个数减一(表示左端点右移)时,如果该数字的个数仍大于0,则依然满足;否则继续输入新数字。

代码

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <deque>
#include <stdio.h>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <iomanip>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define int long long  
#define pii pair<int,int>
using namespace std;
int t[100005];
int shu[100005];
signed main()
{
	IOS;
	
	int n,m;
	cin>>n>>m;
	int you;
	int ji=0;
	int sum=0;
	int zuo=1;
	for(you=1;you<=n;you++)
	{
		cin>>t[you];
		if(shu[t[you]]==0)
		{
			ji++;
		}
		shu[t[you]]++;
		while(ji==m)
		{
			sum+=n-you+1;
			shu[t[zuo]]--;
			if(shu[t[zuo]]==0)
				ji--;
			zuo++;
		}
	}
	cout<<sum<<endl;
	
	
	
	return 0; 
}

B  Two Frogs

题意

河道里n个荷叶排成一排,从第i(<n)个荷叶出发可以跳到第(i,i+ai]个荷叶上,有两只青蛙从第1个荷叶出发,每一步都独立地等概率随机地跳向后边的荷叶,求两只青蛙以相同步数到达第n个荷叶的概率。

思路

采用dp[i][j]来表示采用i步到达j的概率。因为要求两只青蛙相同步数到达第n个荷叶的概率,所以结果应为dp[i][n]的平方和。在计算之前,应先求出a[i]的逆元,即(1/a[i]),表示在i荷叶上选择跳几步的概率。在计算过程中,青蛙在荷叶i上跳跃,可以选择(i,i+a[i]]步,即dp[j][i+k]=(dp[j][i+k]+dp[j-1][i]*inv[i]%mod)%mod,意为第j次跳跃,从第i个荷叶上跳跃,选择一次跳k步,跳到i+k荷叶上的概率是上一次跳跃即第j-1次跳到第i个荷叶上此时从第i个荷叶上选择一个合理数值进行跳跃,概率即为之前跳到i的概率乘以数值选择概率。但是如果一个数一个数的计算,结果会超时,所以应采用差分的思想来计算。

代码

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <deque>
#include <stdio.h>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <iomanip>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define int long long  
#define pii pair<int,int>
using namespace std;
int a[8005];
int dp[8005][8005];//i步到j 的概率 
int mod=998244353;
int c[8005],inv[8005];
int qiu(int a,int b)
{
	int temp=1;
	while(b)
	{
		if(b&1)
			temp=temp*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return temp;
}
signed main()
{
	IOS;
	
	int n;
	cin>>n;
	int i,j;
	int sum;
	for(i=1;i<n;i++)
	{
		cin>>a[i];
	}
	for(i=1;i<n;i++)//求i的逆元 
		inv[i]=qiu(a[i],mod-2);

	dp[0][1]=1;
	for(i=1;i<n;i++)
	{
		for(j=i;j<n;j++)
		{
			c[j+1]=(c[j+1]+dp[i-1][j]*inv[j])%mod;
			c[j+a[j]+1]=(c[j+a[j]+1]-dp[i-1][j]*inv[j]%mod+mod)%mod;
		}
		sum=0;
		for(j=1;j<=n;j++)
		{
			sum=(sum+c[j])%mod;
			c[j]=0;
			dp[i][j]=sum;
		}
	}
	int cnt=0;
	for(i=1;i<n;i++)
	{
		cnt=(cnt+dp[i][n]*dp[i][n]%mod)%mod;
	}
	cout<<cnt<<endl;
	
	
	return 0; 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值