【20170915校内模拟赛】

所有题目开启-O2,评测机效率为4亿左右;


T1 游戏(game)

Description

小R和小H在玩某个双人联机小游戏,一开始两人所操控的角色各有1点力量值,而在游戏中,每通过一关都会掉落一些力量强化道具。奇怪的是,明明是双人小游戏,每关却都会掉落3个相同的力量强化道具,于是两人决定每关每人先拿一个,剩下一个猜拳决定给谁。一个力量强化道具能使一个角色的力量值变为原来的若干整数倍,同一关卡掉落的道具倍率都相同,而不同的关卡可能不同。小R从攻略上找到了一些会产生特殊效果的力量值组合,他想知道哪些组合是按他们的道具分配方式有可能在通过某关时达成的。

Input

第一行一个正整数n,表示力量值组合的个数。

接下来n行,每行两个非负整数ai,bi,表示一个力量值组合。

Output

输出共n行,每行一个”YES”或”NO”表示是否能够达成。

Sample Input

2

2 4

1 8

Sample Output

YES

NO

Hint

本题共10个测试点,其中第x个测试点满足$)n \leq max(4^{i-1},5),ai,bi \leq 10^{x-1} $。

Solution

设所有关卡的bonus累乘=k,那么ai*bi应当等于\(k^3\),因此检验这一性质,并检验是ai,bi,是否为k的倍数即可。注意对于0的判断。时间效率\(O(n \log_{2} aibi)\)

Code

#include <stdio.h>
#define MN 300005
#define R register
#define mid (l+r>>1)
#define Filename "game"
inline int read(){
	R int x; R bool f; R char c;
	for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-');
	for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0');
	return f?-x:x;
}
int n;
inline bool check(int x,int y){
	if (!x&&!y) return 1;
	if ((!x)||(!y)) return 0;
	R int l=1,r=1000000;
	while (l<r){
		if (1ll*mid*mid*mid<1ll*x*y) l=mid+1;
		else r=mid;
	}if (1ll*l*l*l==1ll*x*y)
		return (!(x%l))&&(!(y%l));
	else return 0;
}
int main(){
#ifndef Debug
	freopen(Filename".in","r",stdin);
	freopen(Filename".out","w",stdout);
#endif
	n=read();while(n--){
		if (check(read(),read())) puts("YES");
		else puts("NO");
	}
#ifndef Debug
	fclose(stdin); fclose(stdout);
#endif
	return 0;
}

T2 数字(number)

Description

小R被某人要求做一个报告,报告中要用到一些数据,可惜小R没有,只好自己瞎编一个,于是他随便滚了下键盘,出来一个奇怪的数字。因为明眼人都看的出这个数字是乱打的,所以小R打算强化一下这个数字的可信度,首先他把这一大长串数字分成了n个,然后他决定选出其中k个,把它们乘起来得到最后的数字。众所周知,一个数字末尾的0越多越高大上,所以小R想要最大化得到的数字末尾0的数量。按照套路,请你解决一下。

Input

第一行两个正整数n和k。

接下来n行,每行一个非负整数ai,表示给出的数字。

Output

输出一个整数,表示答案。

Sample Input

3 2

20

50

80

Sample Output

3

Hint

对于20%的数据,\(n \leq 15,ai \leq 10\)

对于30%的数据,\(n \leq 25\)

对于50%的数据,\(n \leq 50,ai \leq 100\)

对于70%的数据,$n \leq 100,ai \leq 10^9 $;

对于100%的数据,$n \leq 15,ai \leq 10^{18} $。

Solution

题意:给出若干个数,从中选出指定数量个相乘,求最大化乘积末尾0的个数。

解题思路:简单DP,预处理出每个数中质因数2与5的个数,然后用\(f_{i,j}\)表示选了i个,有j个5的最大化2的个数,然后DP即可。时间效率\(O(nk \Sigma \log_{5} ai)\)

Code

#include <stdio.h>
#include <string.h>
#define MN 205
#define ll long long
#define R register
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define Filename "number"
inline int read(){
	R int x; R bool f; R char c;
	for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-');
	for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0');
	return f?-x:x;
}
int f[MN][26*MN],v2[MN],v5[MN],n,m,cnt,ans,cntt;
int main(){
#ifndef Debug
	freopen(Filename".in","r",stdin);
	freopen(Filename".out","w",stdout);
#endif
	n=read(),m=read();
	for (R int i=1; i<=n; ++i){
		ll x,y;scanf("%lld",&x);y=x;
		if (!x){
			v2[i]=-1;
			++cntt;
			continue;
		}
		while(!(y%2)) ++v2[i],y>>=1;
		while(!(y%5)) ++v5[i],y/=5; cnt+=v5[i];
	}memset(f,200,sizeof(f));f[0][0]=0;
	if (n-cntt<m){
		puts("1");
#ifndef Debug
	fclose(stdin); fclose(stdout);
#endif
		return 0;
	}if (cntt) ans=1;		
	for (R int j=1; j<=n; ++j){
		if (v2[j]==-1) continue;
		for (R int i=min(m,j); i; --i){
			for (R int k=cnt; k>=v5[j]; --k)
				f[i][k]=max(f[i][k],f[i-1][k-v5[j]]+v2[j]);
		}
	}
	for (R int i=cnt; i>=0; --i) ans=max(ans,min(i,f[m][i]));
	printf("%d\n",ans);
#ifndef Debug
	fclose(stdin); fclose(stdout);
#endif
	return 0;
}

T3 餐厅 (restaurant)

Description

小R最近在玩一款模拟餐厅打工的游戏,其中有一个叠盘子的小游戏小R很喜欢。这个小游戏是这样的:有一个放盘子的机器会在一条直线上运动,机器里装着n个盘子,其中第i个盘子半径为ri,并且如果要放下该盘子,盘子的中心必须放在直线上xi的位置上,小R可以决定放下哪些盘子和放下这些盘子的顺序,盘子可以放在空位上,或者叠在一个上面没有其他盘子的盘子上,但要求被叠的盘子必须包含要叠上去的盘子。小R想要让叠出的盘子尽量高,请你计算出最高的一叠最多能叠几个盘子。

Input

第一行一个正整数n,表示盘子数。

接下来n行,每行两个正整数ri和xi。

Output

输出一个整数,表示答案。

Sample Input

3

3 5

2 4

2 6

Sample Output

2

Hint

对于20%的数据,$n \leq 10 $;

对于50%的数据,$ n \leq 1000$;

对于100%的数据,$ n \leq 10^5 , ri,xi \leq 10^9 $

Solution

题意:给出若干个区间,求一个区间的排列使得这其中的区间满足后一个是前一个的子集,求排列最大长度。

解题思路:按照右端点排序,再按顺序对每个区间DP之前的左端点不大于它的区间,发现可以利用权值线段树加速DP,离散左断点维护即可,注意排序时对同一右端点的处理,时间效率\(O(n \log_{2} n)\)

Code

#include <stdio.h>
#include <algorithm>
#define MN 100005
#define M (1<<17)
#define R register
#define Filename "restaurant"
using namespace std;
inline int read(){
	R int x; R bool f; R char c;
	for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-');
	for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0');
	return f?-x:x;
}
int T[M<<1],n,l[MN],r[MN],tmp[MN],rk[MN];
inline bool cmp(int a,int b){return r[a]<r[b]||(r[a]==r[b]&&l[a]>l[b]);}
inline void A(int k,int v){for (T[k+=M]=v; k; T[k>>=1]=max(T[k],v));}
inline int Q(int l,int r){
    R int res=0;
    for (l+=M-1,r+=M+1; l^r^1; l>>=1,r>>=1){
        if (~l&1) res=max(res,T[l^1]);
        if ( r&1) res=max(res,T[r^1]);
    }return res;
}
int main(){
#ifndef Debug
	freopen(Filename".in","r",stdin);
	freopen(Filename".out","w",stdout);
#endif
    n=read();for (R int i=1; i<=n; ++i)
        l[i]=read(),r[i]=read(),tmp[i]=l[i]=r[i]-l[i],r[i]+=r[i]-l[i],rk[i]=i;
    sort(tmp+1,tmp+n+1);R int ln=unique(tmp+1,tmp+n+1)-tmp-1;
    sort(rk+1,rk+n+1,cmp);for (R int i=1; i<=n; ++i){
        l[rk[i]]=lower_bound(tmp+1,tmp+ln+1,l[rk[i]])-tmp;
        A(l[rk[i]],Q(l[rk[i]],ln)+1);
    }printf("%d",T[1]);
#ifndef Debug
	fclose(stdin); fclose(stdout);
#endif
	return 0;
}
posted @ 2017-09-16 21:55  Melacau  阅读(181)  评论(0编辑  收藏  举报