暑 假 队 测 Round #5

(30+80+30=140pts)
最菜的一次,题目较易,但打的全是暴力。
T2数据过水,假贪心骗了80分。

T1:寻找羔羊
T2:序列
T3:硬币

T1:字符串模拟

假使我们找到一个"agnus",
其左端点是(l),其右端点是(r).((1le l le r le n) )
那么很显然包含它的子串(x) ~ (y)只需要满足(x le l ~)&&(~ r le y)
总数量就是(l imes (n-r+1)).
避免重复统计,我们需要记录上一个"agnus"的结束位置(pre)
统计答案时应是(ans) (+) (=) ((l-pre+1) imes (n-r+1))

(Code):

#include<bits/stdc++.h>
using namespace std;
string st,s="agnus";
int n,ans,pr;
int main(){
	cin>>st;
	n=st.size();
	for(int i=0;i<n;i++)
		if(st.substr(i,5)==s)ans+=(i+1-pr)*(n-i-4),pr=i+1;
	printf("%d
",ans);
	return 0;
}

T2:单调队列

一眼会想到贪心求解,
思路很简单,使得当前温度尽可能的低.
温度不够就降下去重新升温,升温尽可能少
但是会被下面这组数据卡掉:

9
3 3
1 3
1 1
2 2
3 3
4 5
4 5
3 5
3 3

我们要做的其实是维护一段连续的子段。
使得其中的温度单调不降。
单调队列可以轻松解决。

(Code:)

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10; 
int n,a[N],b[N],q[N],ans;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d %d",&a[i],&b[i]);
	int l=1,r=0;
	for(int i=1;i<=n;i++){
		while(l<=r&&a[i]>a[q[r]])r--;
		q[++r]=i;
		while(l<=r&&b[i]<a[q[l]])l++;
		ans=max(ans,i-q[l-1]);
	}
	printf("%d
",ans);
	return 0;
}

T3:背包

01背包的转移方程是 (f[i][j]=f[i-1][j]+f[i-1][j-a[i]])
我们可以先做背包求出所有的(f[i][j])
移项:(f[i-1][j-a[i]]=f[i][j]-f[i-1][j]);
所以当(f[i][j]-f[i-1][j]==0)时此硬币对(j)元钱的组成没有贡献。

(Code:)

#include<bits/stdc++.h>
using namespace std;
const int N=3e5,M=105;
int ans,a[M],f[N+5];
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) 
		scanf("%d",&a[i]);
	f[0]=1;
	for(int i=1;i<=n;i++)
		for(int j=N;j>=0;j--)
			if(f[j]&&j+a[i]<=N)f[j+a[i]]+=f[j];
	for(int i=1;i<=n;i++){
		ans=0;
		for(int j=0;j<=N;j++)
			if(f[j]&&j+a[i]<=N)f[j+a[i]]-=f[j];
		for(int j=1;j<=N;j++)if(f[j])ans++;
		for(int j=N;j>=0;j--)
			if(f[j]&&j+a[i]<=N)f[j+a[i]]+=f[j];
		printf("%d
",ans);
	}
	return 0; 
}
原文地址:https://www.cnblogs.com/Xxhdjr/p/13513973.html