• [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));		
    }
    
    
  • 相关阅读:
    4.28综合练习
    团队项目第一阶段冲刺第六天
    4.27防盗链和代理
    梦断代码阅读笔记3
    团队项目第一阶段冲刺第五天
    4.26抓取猪⼋戒数据
    团队项目第一阶段冲刺第四天
    4.25xpath解析
    4.24aiohttp模块学习
    如何将类数组转化为数组?
  • 原文地址:https://www.cnblogs.com/Anoxiacxy/p/7169717.html
Copyright © 2020-2023  润新知