“蔚来杯“2022牛客暑期多校训练营9(A,B)

A题

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

其实就是长度为 n 的一个序列 a,问有多少个区间中 [1,m] 的数都出现过。

我的想法就是先找出一段出现过[1,m]的区间[a,b],然后往回找可以删左边几个数,就是[1,b]中出现的区间数,再看b右边,直到找到第一个重复的数字,再重复上面的步骤,不过中间得存一下最先出现的数字和最后出现的数字,不过在这里的更新很耗时间,所以t掉了。

#include<bits/stdc++.h>
using namespace std;
int n,m,a[100005],t[100005],l,i,j;
long long int ans;
bool flag;
int main(){
	scanf("%d%d",&n,&m);
	l=m;
	flag=false;
	for ( i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	for ( i=1;i<=n;i++){
		if (t[a[i]]==0 && flag==false){
			t[a[i]]=1;
			l--;
		}
	
		if (l==0 || flag){
			for ( j=1;j<=m;j++)
				t[j]=0;
			l=m;	
			//cout<<"dffd  ";
			for ( j=i;j>=1;j--)
			{   //	cout<<t[a[j]]<<"    ";
				if (t[a[j]]==0){
					t[a[j]]=1;
					l--;
				
				//	cout<<"0";	
				}
			
				if (l==0){
					ans=ans+j;
				//	cout<<ans<<"Cccc";
					flag=true;
					break;
				}
			}
		}
	}
	printf("%lld",ans);
	return 0;
}

但靠着大佬队友用的优化算法,17ms就过了,太强了,不要去记录中间的数字,所以可以减少中间更新所需要的时间。

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

const int N=1e5+7;
int t[N],f[N];

int main(){
	int m,n,i,j,k,ty=0;
	long long ans=0;
	scanf("%d%d",&n,&m);
	memset(t,0,sizeof(t));
	memset(f,0,sizeof(f));
	for(i=1;i<=n;i++)scanf("%d",t+i);
	for(i=1;i<=n;i++){
		if(f[t[i]]==0){
			ty++;
		}
		f[t[i]]++;
		if(ty==m){
			j=i;
			ans+=n-j+1;
			break;
		}
	}
	int cnt=n-1;
	k=1;
	while(cnt>=m){
		f[t[k]]--;
		if(f[t[k]]<=0){
			for(i=j+1;i<=n;i++){
				f[t[i]]++;
				if(t[k]==t[i]){
					j=i;
					break;
				}
			}
			if(i>n)break;
		}
		ans+=n-j+1;
		k++;
		cnt--;
	}
	printf("%lld\n",ans);
}

补题时间

B题

有 n 片荷叶,刚开始两只青蛙在第 1 片荷叶上,在第 i 片荷叶上会跳到 [i+1,i+a[i]] 这个区间中的任意一片荷叶上,问两只青蛙花同样的步数跳到第 n 片荷叶上的概率。

我们最开始卡这里是因为不知道答案怎么表示,用y*y(-1)=1mod(998224902),我们也花了很多时间去理解这种表达方式,所以这道题我们罚坐了好久,后面知道算法要用dp,但就是写不出来dp方程,虽然后面写出来了了,但因为我们多考虑了一层循环,所以一直t。

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
ll n;
ll a[8010];
ll dp[8010][8010],sum[8010],p[8010];
int q[16000];
template <typename T> inline void read(T &WOW) {
    T x = 0, flag = 1;
    char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') flag = -1;
        ch = getchar();
    }
    while (isdigit(ch)) {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    WOW = flag * x;
}
ll qmi(ll a, ll b)
{
    ll res = 1;
    while (b)
    {
        if (b & 1) res = res * a % mod;
        a = a * (ll)a % mod;
        b >>= 1;
    }
    return res;
}
void solve(){
    dp[1][0]=1;
    for(int k=1;k<n;k++){
        for(int i=1;i<=a[k]&&i+k<=n;i++){
            for(int j=q[k];j<=k;j++){
                dp[k+i][j]=(dp[k+i][j]+dp[k][j-1]*p[k]%mod)%mod;
            }
        }
    }
    ll ans=0;
    for(int i=1;i<n;i++){
        ans=(ans+dp[n][i]*dp[n][i]%mod)%mod;
    }
    printf("%lld\n",ans);
}
int main()
{
    read(n);
    for(int i=1;i<n;i++)  read(a[i]),sum[i]=sum[i-1]+a[i];
    for(int i=1;i<=n;i++){
        for(int j=sum[i-1]+1;j<=sum[i];j++){
            q[j]=i;
        }
       
        if(sum[i]>n) break;
    }
  
    for(int i=1;i<=n;i++){
        p[i]=qmi(a[i],mod-2)%mod;
    }
    solve();
}

后面看其他队伍的代码才发现多了一层循环,太难受了。下面是其他大佬的代码,减少了一层循环,所以还是我们的dp方程写的不够完善,导致会t。

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int P = 998244353;
LL qp(LL a, LL k, LL p){
	LL ans = 1;
	while (k){
		if (k & 1) ans = ans * a % p;
		k >>= 1;
		a = a * a % p;
	}
	return ans;
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	LL n;
	cin >> n;
	vector <LL> inv(n + 1);
	inv[1] = 1;
	for (int i = 1; i <= n; i ++ )
		inv[i] = qp(i, P - 2, P);
	vector <LL> a(n);
	for (int i = 1; i < n; i ++ )
		cin >> a[i];
	vector dp(n + 1, vector<LL>(n + 2, 0));
	dp[0][1] = 1;
	for (int j = 0; j < n; j ++ ){
		if (j){
			for (int i = 1; i <= n; i ++ )
				dp[j][i] = (dp[j][i] + dp[j][i - 1]) % P;
		}
		for (int i = 1; i < n; i ++ ){
			dp[j + 1][i + 1] = (dp[j + 1][i + 1] + inv[a[i]] * dp[j][i] % P) % P;
			dp[j + 1][i + a[i] + 1] = (dp[j + 1][i + a[i] + 1] - inv[a[i]] * dp[j][i] % P) % P;
		}
	}
	LL ans = 0;
	for (int j = 1; j < n; j ++ )
		ans = (ans + dp[j][n] * dp[j][n] % P) % P;
	cout << ans << "\n";
	return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值