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;
}