2020.02.05【NOIP普及组】模拟赛C组

0最大值
1火柴
2游戏
3Hack比赛

T1

题目描述

给定n个数,{x1,x2,...,xn}要求从中选出至少一个数,至多n个数,使得乘积之和最大。

输入

第一行整数n,表示有多少个数
接下来n行,每行一个整数xi,-10 ≤xi≤ 10

输出

输出一行,表示最大乘积

样例输入

Sample Input1:

3
-1
2
-4

Sample Input2:

3
3
2
-4

样例输出

Sample Output1:

8

Sample Output2:

6

数据范围限制

对于70%的数据:1 ≤ n ≤ 9
对于100%的数据: 1 ≤ n ≤ 18,-10 ≤xi≤ 10

这题要注意,有很多陷阱
1:全是0
2:只有一个数,那个数是负数
3:一个负数,其他全是0
处理好这些,你就能对了

#include<iostream>
#include<cstdio>
using namespace std;
long long m,n,k,x=1,a[10010],y=1,o;
int main(){
	freopen("max.in","r",stdin);
	freopen("max.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		if(a[i]>0)x=x*a[i];
		if(a[i]<0){
			k++;
			y=y*a[i];
		}
		if(a[i]==0)o++;
	}
	if(n==k&&k==1){
		cout<<a[1];
		return 0;
	}
	if(o==n){
		cout<<0;
		return 0;
	}
	if(k==1&&o==n-1){
		cout<<0;
		return 0;
	}
	long long max=-10000000;
	if(k%2==1){
		for(int i=1;i<=n;i++){
			if(a[i]<0){
				if(a[i]>max)max=a[i];
			}
		}
		y=y/max;
	}
	cout<<x*y;
	return 0;
}

T2

题目描述

给定一个N位的数,将火柴棍重新排列后,能得到的最大的数是多少?
注意不能多出或者少一位, 火柴棍要全部用上.

输入

第一行整数T,表示数据组数
接下来T行,每行一个整数N, 然后是N位数,表示原来的数,可能会有前导0,中间用空格隔开。

输出

对于每组数据,输出一行,最大的能得到的数是多少。

样例输入

3
1 3
3 512
3 079

样例输出

5
977
997

数据范围限制

对于20%的数据:1 ≤ n ≤ 10
对于60%的数据:1 ≤ n ≤ 1000
对于100%的数据: 1 ≤ n ≤ 100000,1 ≤T≤ 10

贪心加爆力
用一共的火柴棒
判断是否当前可行
可行就枚举数字(从大到小)

#include<iostream>
#include<cstdio>
using namespace std;
long long m,n,k,x,y;
int a[10]={6,2,5,5,4,5,6,3,7,6};
int main(){
	freopen("match.in","r",stdin);
	freopen("match.out","w",stdout);
	int t;
	cin>>t;
	while(t--){
		k=0;
		string s;
		cin>>n>>s;
		for(int i=0;i<n;i++){
			k=k+a[s[i]-48];
		}
		x=0;
		y=n;
		while(2*y<=k&&7*y>=k&&x<=n&&y>0&&k>0){
			x++;
			for(int j=9;j>=0;j--){
				if((k-a[j]>=2*(y-1)&&(7*(y-1)>=k-a[j])&&y>1)||(y==1&&k==a[j])){
					y--;
				    k-=a[j];
				    cout<<j;
				    break;
				}
			}
		}
		cout<<endl;
	}
	return 0;
}

T3

题目描述

Guyu Guo和Tube Lu正在玩一个游戏:Lu默想一个1和n 之间的数x,然后Guo尝试猜出这个数。
Guo能提出m个这样的问题: “未知数是否能被yi整除?”
游戏按照如下流程进行:Guo先给出他想问的全部m个问题,然后Lu对所有问题依次以“是”或“否”作答。得到m个问题的答案之后,Guo就要给出他的猜测。
Guo写了一个程序帮他以最优的方式提出这m个问题,现在他想知道在保证得到一个确定的答案下,最少可以问多少个问题,即m的最小值。但是Guo正忙于吃漂亮学姐送他的糖果而无暇改代码(送糖果的学姐十分多,以至于有许多糖果快要过期了),所以他找到了你,希望你来帮他解决这个问题。

输入

一行,一个整数n

输出

一行,一个整数m

样例输入

【样例输入1】

4

【样例输入2】

8

样例输出

【样例输出1】

3

【样例输出2】

6

样例1解释:

Guo依次提问能否被2,3,4整除,就可以得到确定答案。
比如Lu回答能被2,4整除,不能被3整除,则确定答案为4

样例2解释:

Guo依次提问能否被2,3,4,5,7,8整除,总共需要6次。

数据范围限制

对于20%的数据:1 ≤ n ≤ 20
对于60%的数据:1 ≤ n ≤ 1000
对于100%的数据: 1 ≤ n ≤ 100000

数学+枚举
肯定和质数有关
先用塞法塞出质数
现在来判断:
一个数,它到底说不说和之前说过的数有关
只要它之前说过的数乘起来等于它,它就不用说
那就变成了一个质数的幂在N已内出现过几次

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
bool f[100010];
long long w;
int n,ans;
int main()
{
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	cin>>n;
	memset(f,false,sizeof f);
	f[1] = true;
	ans = 0;
	for(int i=2;i<=n;i++)
		if(f[i] == false)
			for(int j=2;j<=n/i;j++)
				f[i*j]=true;
	for(int i=2;i<=n;i++)
		if(f[i]==false)
		{
			w=i;
			while(w<=n)
			{
				ans++;
				w*=i;
			}
		}
	cout<<ans<<endl;
	return 0;
}

T4

题目描述

Codefires round马上就要结束了!ZCC已经通过做题得到了C分。但他惊讶地发现,房间里的其他选手也都解决了最难的题。ZCC根据经验断定大多数的选手都会FST的!当然,除去rating最高的选手Memset137。在此之前,ZCC想要hack他们来使他的得分更高。除了ZCC,房间里有N个选手,他们已经被按照rating从小到大排序了(所以Memset137是排在第N个的选手)。当ZCC成功hack了第i个选手时,他会获得i分的收入。你可以假设ZCC hack技术高超,百发百中,可以hack除了Memset137和自己以外的所有选手,而且在此期间没有其他选手干扰。
由于ZCC有着谦虚的美德,他不想让自己的得分太高。ZCC想要知道,存在着多少种不同的选择一些人hack的方案,使得他的得分在L和R(C≤L≤R<C+N)之间。
显然答案会很大,请输出答案对998244353取模后的结果。

输入

一行,四个整数n,c,l,r分别表示n个选手,当前分数为c,希望得分在l到r之间

输出

输出一行,方案数

样例输入

Sample Input1:

3 0 1 2

Sample Input2:

5 13 14 17

Sample Input3:

100 0 23 59

样例输出

Sample Output1:

2

Sample Output2:

6

Sample Output3:

90567

数据范围限制

对于20%的数据: 1≤N≤50;
对于50%的数据: 1≤N≤2000;
对于100%的数据: 1≤N≤100000, 1≤C≤1000000,C≤L≤R<C+N;

这肯定是一道DP
我们马上想到,设第i个数前(包括i)获得j分的方案
时间复杂度:O(N^2)
爆了
来举个列子:
假设有M个数(1~M),那它们的和就是(M-1)*M,也就是说最多选√N个数,所以可以把i的循环优化,状态变成选了i个积分为j的方案数

#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
int m,n,k,x,y,l1,r;
int f[500][100001];
int main(){
	freopen("hack.in","r",stdin);
	freopen("hack.out","w",stdout);
	cin>>n>>k>>l1>>r;
	l1=l1-k;r=r-k;k=k-k;
	f[0][0]=1;
	for(int i=1;i<=sqrt(n)+131;i++){
		for(int j=i;j<=r;j++){
			f[i][j]=f[i][j-i]+f[i-1][j-i];
			//f[i][j-i]的含义:
			//相当于把选了的数向右位移1(全部加1)
		
			f[i][j]=f[i][j]%998244353;
		}
		for(int j=l1;j<=r;j++){
			k=k+f[i][j];
			k=k%998244353;
		}
	}
	cout<<k;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值