[noip模拟赛2017.7.10]

全国信息学分区联赛模拟试题(一)

【试题概览】

题目名称 漂亮字串 Set Prison
提交文件 bs.* set.* prison.*
输入文件 bs.in set.in prison.in
输出文件 bs.ans set.ans prison.ans
时间限制 1s 1s 1s
空间限制 128MB 128MB 128MB
题目来源 Codejam codejam cadejam

漂亮字串

【题目描述】

Caima 认为 O 和 X 是最优美的两个字母,由 O、X 组成的串是最优美的串。在这些最优美的串中, 如果任意只包含 X 的子串,长度不超过 maxX,任意只包含 O 的子串,长度不超过 maxO,且整个串 最多有 countO 个 O,countX 个 X。那么这个就是超级优美无敌串。
现在 Caima 想知道最长的超级优美无敌串有多长,希望你告诉他。

【输入格式】

输入包含多行,至文件结束为止;
每行四个数,依次是 countO、countX、maxO、maxX。

【输出格式】

每组数据输出一行,一个数表示最长的超级优美无敌串的长度。

【数据规模】

0<=countO,countX,maxO,maxX<=1000000

【输入样例】

10 10 0 0

3 5 1 1

【输出样例】

0

7

【注意事项】

第二个样例的解释:”XOXOXOX”
最多 1000 组数据,其中 30%的数据 0<=countO,countX,maxO,maxX<=20,且数据组数不超过 20 组。

题解

直接贪心,不妨设O的个数小于X的个数,
那么将O排成一行,中间插入X,在满足其他条件的情况下一定是最优的,可以O(1)得到结果,代码如下:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#define LL long long

using namespace std;

int co,cx,mo,mx;
int main(){
	freopen("bs.in","r",stdin);
	freopen("bs.out","w",stdout);
	while(scanf("%d%d%d%d",&co,&cx,&mo,&mx)!=EOF){
		if(mo==0){
			printf("%d
",min(cx,mx));
			continue;
		}
		else if(mx==0){
			printf("%d
",min(co,mo));
			continue;
		}
		else if(co==cx){
			printf("%d
",co+cx);
			continue;
		}
		else if(co>cx){
			int to=cx+1;
			int ans=(int)min((LL)co,(LL)to*mo)+cx;
			printf("%d
",ans);
			continue;
		}
		else if(co<cx){
			int tx=co+1;
			int ans=(int)min((LL)cx,(LL)tx*mx)+co;
			printf("%d
",ans);
		}
	}
	return 0;
} 

Set

【题目描述】

现在给你一些连续的整数,它们是从 A 到 B 的整数。一开始每个整数都属于各自的集合,然后你 需要进行如下操作:
每次选择两个属于不同集合的整数,如果这两个整数拥有大于等于 P 的公共质因数,那么把它们 所在的集合合并。
反复上述操作,直到没有可以合并的集合为止。
现在 Caima 想知道,最后有多少个集合。

【输入格式】

一行,三个整数 A,B,P。

【输出格式】

一个树,表示最终集合的个数。

【数据规模】

A<=B<=100000;2<=P<=B。

【输入样例】

10 20 3

【输出样例】

7

【注意事项】

有 80%的数据 B<=1000.
样例解释{10,20,12,15,18},{13},{14},{16},{17},{19}。

题解

是一个合并的问题,考虑用到并查集,先线性筛出要用到的素数,每次将该素数倍数的数合并为一个集合,复杂度可看作线性

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#define LL long long

using namespace std;


int prime[100100];
bool flag[100100];
void pre(){
	for(int i=2;i<=100000;i++){
		if(!flag[i])prime[++prime[0]]=i;
		for(int j=1;j<=prime[0]&&i*prime[j]<=100000;j++){
			flag[i*prime[j]]=true;
			if(i%prime[j]==0)break;
		}
	}
}


int Fa[100100];
int findf(int x){
	if(x==Fa[x])return x;
	return Fa[x]=findf(Fa[x]);
}
void mergef(int x,int y){
	Fa[findf(x)]=findf(y);
}
int A,B,P,ans;
int main(){
	freopen("set.in","r",stdin);
	freopen("set.out","w",stdout);
	pre();
	scanf("%d%d%d",&A,&B,&P);
	for(int i=A;i<=B;i++)Fa[i]=i;
	for(int i=1;i<=prime[0];i++){
		if(prime[i]<P)continue;
		if(prime[i]>B)break;
		int s=(A/prime[i])*prime[i];
		if(s<A)s+=prime[i];
		for(int j=s;j<=B;j+=prime[i]){
			mergef(s,j);
		}
	}
	for(int i=A;i<=B;i++)
		if(findf(i)==i)ans++;
	printf("%d
",ans);
	return 0;
}

Prison

【题目描述】

Caima 王国中有一个奇怪的监狱,这个监狱一共有 P 个牢房,这些牢房一字排开,第 i 个仅挨着第 i+1 个(最后一个除外)。现在正好牢房是满的。
上级下发了一个释放名单,要求每天释放名单上的一个人。这可把看守们吓得不轻,因为看守们 知道,现在牢房中的 P 个人,可以相互之间传话。如果某个人离开了,那么原来和这个人能说上话的 人,都会很气愤,导致他们那天会一直大吼大叫,搞得看守很头疼。如果给这些要发火的人吃上肉, 他们就会安静点。 现在看守们想知道,如何安排释放的顺序,才能使得他们花费的肉钱最少。

【输入格式】

第一行 2 个数 P 和 Q,Q 表示释放名单上的人数;
第二行 Q 个数,表示要释放哪些人。

【输出格式】

仅一行,表示最少要给多少人次送肉吃。

【数据规模】

1<=P<=1000;1<=Q<=100。

【输入样例】

20 3

3 6 14

【输出样例】

35

【注意事项】

Q<=P;且 50%的数据 1<=P<=100;1<=Q<=5。

题解

考虑记忆化搜索,对于每段牢房,我们枚举最先放出去的犯人,
之后左边的犯人和右边的犯人就没有任何关系了,
那么dp[l][r]=r-l+dp[l][m]+dp[m][r],
注意可以在0和n+1的位置插一个空牢房,以免特殊情况的判断

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#define LL long long
#define INF (1<<30)
using namespace std;
int P,Q;
int rls[200];
int dp[200][200];
bool Find[200][200];
int dfs(int l,int r){
	if(Find[l][r])return dp[l][r];
	Find[l][r]=true;
	if(l+1==r)return dp[l][r]=0;
	dp[l][r]=INF;
	for(int i=l+1;i<=r-1;i++)
		dp[l][r]=min(dfs(l,i)+dfs(i,r),dp[l][r]);
	dp[l][r]+=rls[r]-rls[l]-2;
	return dp[l][r];
}
int main(){
	freopen("prison.in","r",stdin);
	freopen("prison.out","w",stdout);
	scanf("%d%d",&P,&Q);
	for(int i=1;i<=Q;i++)
		scanf("%d",&rls[i]);
	rls[0]=0;rls[Q+1]=P+1;
	printf("%d
",dfs(0,Q+1));		
}

原文地址:https://www.cnblogs.com/Anoxiacxy/p/7169717.html