【题解】 模拟赛3题解

T1

利用一个变量记录目前连号的个数
再用一个变量记录最多的个数
如果满足 a [ i ] = = a [ i − 1 ] + 1 a[i]==a[i-1]+1 a[i]==a[i1]+1,那么连号个数+1
否则连号个数重置为1
边统计边记录最大值

#include
using namespace std;

const int N = 1e4+100;

int n,Max = 0;
int a[N];

int main(){
	scanf("%d",&n);
	for (int i = 1; i <= n; i++) scanf("%d",&a[i]);
	Max = 1;
	int nows = 1;
	for (int i = 2; i <= n; i++)
	  if (a[i] == a[i-1]+1) nows++;
	  else Max = max(Max,nows) , nows = 1;
	Max = max(Max,nows);
	printf("%d",Max);
}

T2

类似于括号匹配
一个下坡和一个上坡对应一个谷地
我们利用一个变量记录前面是否有下坡
如果当前出现了一个上坡并且前面有下坡的话那么当前的上坡和前面的下坡匹配可以形成一个谷地,重置记录下坡的变量
最后累计总数即可

#include
using namespace std;

const int N = 1e5+10;
int ans = 0,n;
bool Z = 0;

int main(){
	scanf("%d",&n);
	int x,la;
	cin>>la;
	for (int i = 1; i < n; i++){
		scanf("%d",&x);
		if (x<la) Z = 1;//出现下坡
		if (x>la && Z) ans++,Z = 0;//上坡和下坡匹配
		la = x;
	}
	cout<<ans;
}

T3

我们首先考虑暴力
枚举每一个人,看看这个人是否能给别人当福星
如果能,那个人的福星个数就+1
时间复杂度 O ( n 2 ) O(n^2) O(n2)

我们仔细考虑,我们中间有些过程是不是重复冗余的?
比如说第有两个人x和y,他们的幸运数字相同,那么累加过程是不是只要执行一次就行了呢?
第二次累加是不是就是重复第一次累加的过程?

基于这个思路,我们需要知道每个数字都出现了几次。
所以我们自然而然地就想到了桶

没错,我们用桶的思想去做这道题
首先用一个桶 a [ i ] a[i] a[i]表示有几个人幸运数字为i
再用一个桶 f [ i ] f[i] f[i]表示数字为 i i i的人有几个福星

那么,对于数字为i的人来说他能给谁当福星呢?
显然能给编号为 i ∗ j ( j ∈ ( 1 , M a x / i ) ) i*j(j\in(1,Max/i)) ij(j(1,Max/i))的人当福星
我们在上面已经统计了数字为i的人的人数
那么我们只需要令 f [ i ∗ j ] + = a [ i ] f[i*j]+=a[i] f[ij]+=a[i]就可以啦

假设第i个人的幸运数字为 c [ i ] c[i] c[i]
输出就是 f [ c [ i ] ] − 1 f[c[i]]-1 f[c[i]]1

#include
using namespace std;

const int N = 1e6+10;

int n;
int a[N],f[N],c[N];
int Max = 0;

int main(){
	scanf("%d",&n);
	for (int i = 1; i <= n; i++) scanf("%d",&c[i]) , Max = max(Max,c[i]) , a[c[i]]++;//放进桶里面
	for (int i = 1; i <= Max; i++)
	  if (a[i])//如果当前数字出现过
	    for (int j = 1; j <= Max/i; j++)
	      f[i*j]+=a[i];//累加幸运数字
	for (int i = 1; i <= n; i++) printf("%d ",f[c[i]]-1);
}

T4

这是一道01背包问题
首先这道题有两个要素
一是他自己喜欢的题目
二是老师布置的作业
对于自己喜欢的题目,题目中没有特别的要求,只要求做的题尽可能多就可以,当然这点也需要注意
对于老师布置的题目,有两个要素,一是时间,二是分数
由于我们希望尽可能花多的时间去刷题,在老师的作业上面我们花的时间就要尽可能少
也就是希望我们在一个有限的时间里面,获取尽可能多的分数
这两个要素就满足了背包的要求
我们将时间理解为体积,将分数理解为价值
那么数组 f [ i ] f[i] f[i]就表示我们用时间i所能获得的最大分数
转移就和01背包相同
那么第几个时间段我们可以几个呢?

我们就从第一个时间从前往后找,找到第一个 f [ i ] > k f[i]>k f[i]>k i i i就是我们所需要花的最小时间

那么余下的时间我们就都能够用来刷题呢
我们希望刷题的数量尽可能多,那就是每一道题的刷题时间都尽可能小
于是我们只要把刷题的时间从小到大排序
然后依次做下去知道体力耗完即可

#include
using namespace std;

const int N = 1e5+10;
int n,m,k,r;
int t[N],zt[N],zf[N];
int f[N];

int main(){
	scanf("%d %d %d %d",&n,&m,&k,&r);
	for (int i = 1; i <= n; i++) scanf("%d",&t[i]);
	sort(t+1,t+n+1);
	for (int i = 1; i <= m; i++) scanf("%d",&zt[i]);
	for (int i = 1; i <= m; i++) scanf("%d",&zf[i]);
	for (int i = 1; i <= m; i++)
	  for (int j = r; j >= zt[i]; j--)
	    f[j] = max(f[j],f[j-zt[i]]+zf[i]);
	int Mint = 0;
	for (Mint = 1; Mint <= r; Mint++)
	  if (f[Mint] >= k) break;
	r = r-Mint;
	int Ans = 1;
	while (t[Ans]<=r) r-=t[Ans++];
	cout<<Ans-1;
}

你可能感兴趣的:(题解,滨小之旅)