一道十分简明的序列题
题意简述
$n$ 个人,每个人都要给一个 $[ 1 ,m ]$ 之间的整数,且每个 $[ 1 , m ]$ 间的整数需至少给一个人。
每个人有一个阈值 $a_i$ ,若与第 $i$ 个人拥有相同数字的人数至少为 $a_i$ (包括自己),那么他就是高兴的。
多次询问,每次一个 $m$ ,求最多高兴人数。
解决方案
易证得:按 $a_i$ 排序,一定是从前往后一段一段分组。
设 $f_i$ 表示前 $i$ 个人都高兴,至多分为几段。
所以我们可以写出动态转移方程。
f[j]=f[i]=max( f[j]+1,f[i] ) (0<=j<=i-a[i] a[i]<=j)
代码
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+100;
int n,m;
int T;
int a[N];
int f[N];
int ans[N];
int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
//2024/1/16
int main()
{
m=read();
for(int i=1;i<=m;i++) a[i]=read();
sort(a+1,a+m+1);//按a[i]排序,一定是从前往后一段一段分组。
for(int i=1;i<=m;i++)
{
if(i>=a[i])
{
f[i]=f[i-a[i]]+1;
ans[f[i]+m-i]=max(i,ans[f[i]+m-i]);
}//高兴人数为i,整数范围至多为f[i]+m-i
else ans[m-a[i]+1]=max(i,ans[m-a[i]+1]);//高兴人数为i,整数范围至多为m-a[i]+1
f[i] = max(f[i], f[i - 1]);
}//dp:f[i]=max{f[j]+1} (0<=j<=i-a[i] a[i]<=j)
for(int i=m;i>=1;i--) ans[i]=max(ans[i],ans[i+1]);
T=read();
while(T--)
{
n=read();
printf("%d\n",ans[n]);
}
return 0;
}
标签:ch,int,max,CF1793E,read,while,ans
From: https://www.cnblogs.com/tangml/p/18553480