暑 假 队 测 Round #5

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

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

T1:字符串模拟

假使我们找到一个"agnus",
其左端点是\(l\),其右端点是\(r\).(\(1\le l \le r \le n\) )
那么很显然包含它的子串\(x\) ~ \(y\)只需要满足\(x \le l ~\)&&\(~ r \le y\)
总数量就是\(l \times (n-r+1)\).
避免重复统计,我们需要记录上一个"agnus"的结束位置\(pre\)
统计答案时应是\(ans\) \(+\) \(=\) \((l-pre+1) \times (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\n",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\n",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\n",ans);
	}
	return 0; 
}
posted @ 2020-08-16 20:13  Isenthalpic  阅读(93)  评论(0编辑  收藏  举报