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

题目编号标题
0权势二进制
1num
2复仇者vsX战警之训练(train)
3第四题

T1

题目描述

一个十进制整数被叫做权势二进制,当他的十进制表示的时候只由0或1组成。例如0,1,101,110011都是权势二进制而2,12,900不是。
当给定一个n的时候,计算一下最少要多少个权势二进制相加才能得到n。

输入

k组测试数据。
第1行给出一个整数k (1<=k<=10)
第2到k+1行每行一个整数n(1<=n<=1000000)

输出

输出答案占k行。
每行为每个n的答案。

样例输入

1
9

样例输出

9

数据范围限制

俗话说的好:样例都是骗人的
我想到的:打表加爆力
挂了
其实只要输出最大的那—位就行了
原因就是只要保证最大的位了,其他的就可以写出来了,因为如果要加1位,那么剩余的每一位都可以+1。时间复杂度n的十进制位数

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,k,f[1000100];
int main(){
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
	int t;
	cin>>t;
	while(t--){
		cin>>n;
		k=0;
		while(n!=0){
			if(n%10>k)k=n%10;
			n=n/10;
		}
		cout<<k<<endl;
	}
	return 0;
}

T2

题目描述

   KC邀请他的两个小弟K和C玩起了数字游戏。游戏是K和C轮流操作进行的,K为先手。KC会先给定一个数字Q,每次操作玩家必须写出当前数字的一个因数来代替当前数字,但是这个因数不能是1和它本身。例如当前数字为6,那么可以用2,3来代替,但是1和6就不行。现在规定第一个没有数字可以写出的玩家为胜者。K在已知Q的情况,想知道自己作为先手能不能胜利,若能胜利,那么第一次写出的可以制胜的最小数字是多少呢?整个游戏过程我们认为K和C用的都是最优策略。

输入

只包括一个正整数Q

输出

第一行是1或2,1表示K能胜利,2表示C能胜利。
若K能胜利,则在第二行输出第一次写出的可以制胜的最小数字,若是第一次	就无法写出数字,则认为第一次写出的可以制胜的最小数字为0。
说明:若C能胜利,不用输出第二行,输出2即可。

样例输入

6

样例输出

2

数据范围限制

对于30%的数据,Q<=50; 对于100%的数据,Q<=10^13。

这题想一想,其实不难发现,自己获胜只能让对方给自己说一个质数,这时,我们想到了质因数分解,对方获胜只有我们给他说一个质数,所以我们只要判断n的质因数里是否存在2个以上的数

#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
long long m,n,k,x,y;
int main(){
	freopen("num.in","r",stdin);
	freopen("num.out","w",stdout);
	cin>>n;
    k=1;
    for(int i=2;i<=sqrt(n);i++){
    	if(n%i==0){
    		k=0;
    		break;
		}
	}
	if(k==1){
		cout<<1<<endl<<0;
		return 0;
	}
	y=10000000000000;
	k=10000000000000;
	x=2;
	m=0;
	long long m1=n;
	while(x*x<=m1){
		while(n%x==0){
			if(x<y)y=x;
			else if(x<k)k=x;
			m++;
			n=n/x;
			if(m>2){
				cout<<1<<endl<<y*k;
				return 0;
			}
		}
		x++;
	}
	if(m==2){
		if(n!=1){
			cout<<1<<endl<<y*k;
		}
	}
	else
	cout<<2;
	return 0;
}

T3

题目描述

月球上反凤凰装甲在凤凰之力附身霍普之前,将凤凰之力打成五份,分别附身在X战警五大战力上面辐射眼、白皇后、钢力士、秘客和纳摩上(好尴尬,汗)。
在凤凰五使徒的至高的力量的威胁下,复仇者被迫逃到昆仑的一座山上,因为凤凰五使徒监视不到那里。
霍普加入了复仇者,为了磨练自己,她在n个山峰之间跳跃。
这n个山峰在一条直线上,每个山峰都有不同的高度,只知道这些山峰在水平上相对位置。霍普可以将这些山峰左右移动但不能改变他们的相对位置(要保证两两山峰间距为整数且大于等于1)。霍普要从最矮的山峰开始跳,每次跳向第一个比现在她所在的山峰高的山峰,一共跳n-1次,由于能力有限,每次跳跃的水平距离小于等于d。
霍普想知道如何移动这些山峰,使得在可以经过所有的山峰并跳到最高的山峰上的基础下,又要使最矮的山峰和最高的山峰的水平距离最远,霍普要你求出最远的水平距离。如果无论如何也不能经过所有的山峰并跳到最高的山峰上,那么输出-1。

输入

输入文件名为attack.in。
本题每个测试点有多组数据,
在第一行中有一个整数t,表示数据的数目(t<=500)
对于每组数据:
第一行包含两个整数n(1≤n≤1000)和d(1≤d≤1000000)。
下一行包含n个整数,给出n个山峰的高度,输入顺序即为山峰在水平上的相	对顺序。在每个数据中,所有的高度都是唯一的。

输出

 输出文件名为attack.out。
输出共t行。
对于每组数据输出最远的水平距离。如果无论如何也不能经过所有的山峰并跳到最高的山峰上,那么输出-1。

样例输入

3
4 4
20 30 10 40
5 6
20 34 54 10 15
4 2
10 20 16 13

样例输出

3
3
-1

数据范围限制

【数据说明】  
对于100%的数据,1≤n≤1000,1≤d≤1000000

哇!刚看到题就被吓倒了,连暴力都不会打,骗分也不会骗,啥也没交
正解:SPFA+差分约束系统

思路:
把这道题目分解,可以分解为两个条件。
1、两个山峰之间水平距离至少为1(因为山峰不能再同一位置上)。
2、霍普每次最多跳d的水平距离。对于第一个条件,对于两个相邻的山峰,相对位置(即输入顺序)大的向相对位置小的连一条-1的边。对于第二个条件,对于两个高度排名相邻的山峰,相对位置小的向相对位置大的连一条d的边。然后比较最高和最低的山峰,从相对位置小的那个山峰出发,做一次最短路(小),输出到相对位置大的山峰的距离。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
long long m,n,k,x,y,d;
struct node{
	int d,w;
}a[1001];
long long dis[1001],v[1001],f[1000010],r[1001];
int b[2001][5],tot,head[1001];
void ljb(int x,int y,int d){//邻接表
    tot++;
    b[tot][2]=y;
    b[tot][3]=d;
    b[tot][4]=head[x];
    head[x]=tot;
}
bool cmp(node x,node y){
	return x.d<y.d;
}
void spfa(int x,int gg){
	memset(dis,1,sizeof(dis));
	memset(v,0,sizeof(v));
	memset(r,0,sizeof(r));
	dis[x]=0;
	f[1]=x;
    v[x]=1;
    int hd=0,tl=1;
    while(hd<=tl){
    	hd++;
    	int x1=f[hd];
    	for(int i=head[x1];i;i=b[i][4]){
    		int y=b[i][2];
    		if(dis[y]>dis[x1]+b[i][3]){//确定方案
    		//大家会不会以为要的不是最大距离,而为啥这里是最小呢?
    		//应为你把它们山移动和其它山的距离也有关
    		//-1是让距离减到一个最大的位置
    			dis[y]=dis[x1]+b[i][3];
    			if(v[y]==0){
    				v[y]=1;
    				tl++;
    				f[tl]=y;
    				r[y]++;
    				if(r[y]>n){
    					cout<<-1<<endl;
    					return;
					}//判断环
				}
			}
		}
		v[x1]=0;
	}
	if(gg==1)cout<<dis[a[n].w];
	else cout<<dis[a[1].w];
	cout<<endl;
}
int main(){
	freopen("attack.in","r",stdin);
	freopen("attack.out","w",stdout);
	int t;
	cin>>t;
	while(t--){
		memset(b,0,sizeof(b));
		memset(head,0,sizeof(head));
		tot=0;
		cin>>n>>d;
		for(int i=1;i<=n;i++){
			cin>>a[i].d;
			a[i].w=i;
			ljb(i,i-1,-1);
		}//相邻连-1
		sort(a+1,a+1+n,cmp);
		for(int i=1;i<n;i++){
			if(a[i].w>a[i+1].w){
				ljb(a[i+1].w,a[i].w,d);
			}
			else{
				ljb(a[i].w,a[i+1].w,d);
			}
		}//大小相邻连d
		if(a[1].w<a[n].w){
			spfa(a[1].w,1);
		}
		else{
			spfa(a[n].w,n);
		}
	}
	return 0;
}

T4

……

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值