[jzoj]2018.07.12【NOIP普及组】模拟赛D组:解题报告

1.权势二进制

题目:

一个十进制整数被叫做权势二进制,当他的十进制表示的时候只由0或1组成。例如0,1,101,110011都是权势二进制而2,12,900不是。

当给定一个n的时候,计算一下最少要多少个权势二进制相加才能得到n。

输入:

k组测试数据。

输出:

输出答案占k行。

每行为每个n的答案。

数据范围:

第1行给出一个整数k (1<=k<=10)

第2到k+1行每行一个整数n(1<=n<=1000000)

思路:

答案就是n中最大的位,原因就是只要保证最大的位了,
其他的就可以写出来了,因为如果要加1位,那么剩余的每一位都可以+1。

时间复杂度n的十进制位数

Code:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cctype>
#include<cmath>
using namespace std;
int ans = 0;
int read()
{
    int ret = 0;
	int w = 1;
	char ch = getchar();
    while(ch > '9' || ch < '0')
	{
		if(ch == '-')
			w = -1;
		ch = getchar();
	}
    while(ch >= '0' && ch <= '9')
		ret = (ret << 3) + (ret << 1) + ch - '0',ch = getchar();
    return ret * w;
}
void print(int x)
{
    if(x < 0)
		putchar('-'),x = -x;
    if(x > 9)	
		print(x / 10);
    putchar(x % 10 + '0');
}
int main()
{
	//freopen("a.in","r",stdin);
	//freopen("a.out","w",stdout);
    int ans = 0,n;
    int k;
    k = read();
    for(int i = 1;i <= k;i++)
    {
    	ans = 0;
    	n = read();
    	while(n)
    	{
    		ans = max(ans,n % 10);
        	n /= 10;
		}
		print(ans);
		puts("");
	}
}

2.num

题目:

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即可。

数据范围:

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

思路:

1.Q是1或质数,此时小K只能选0,胜利。
2.Q是两个质数的积,小K只能选这两个质数中的一个,对方无法写出,对方胜利。
3.Q是多个质数的积,小K有必胜策略,胜利。
(当Q = 2 * 2 * 3 = 12时,小K选4,对方选择2。小K无法选择,胜利)

Code:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cctype>
#include<cmath>
#include<queue>
#define ll long long
using namespace std;
ll n,ans;
queue<ll>q;
int main()
{
    //freopen("num.in","r",stdin);
    //freopen("num.out","w",stdout);
    cin >> n;
    for(ll i = 2;i * i <= n;i++)
		while(n % i == 0)
			q.push(i),n /= i;
    if(n != 1)
		q.push(n);
    if(q.size() == 2)
		printf("2\n");
    else if(q.size() == 1)
		printf("1\n0\n");
    else
    {
        printf("1\n");
        ans = q.front();
        q.pop();
        printf("%lld\n",ans * q.front());
    }
    return 0;
}

3.复仇者vsX战警之训练

题目:

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

输入:

本题每个测试点有多组数据,
在第一行中有一个整数t,表示数据的数目
对于每组数据:
第一行包含两个整数n和d
下一行包含n个整数,给出n个山峰的高度,输入顺序即为山峰在水平上的相对顺序。在每个数据中,所有的高度都是唯一的。

输出:

输出共t行。

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

数据范围:

对于100%的数据,1≤n≤1000,1≤d≤1000000,t<=500

思路:

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

Code:

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
const long long maxlongint = 2147483647;
const long long mo = 1000000007;
const long long N = 2005;
using namespace std;
struct ddx
{
    int h,p;
}a[N];
int T,last[N * 2],to[N * 2],ne[N * 2],v[N * 2],dis[N],n,dd,tot,d[N * N],pp,num[N];
bool bz[N];
inline int read()
{
    int ret = 0,w = 0; 
	char ch = 0;
    while(!isdigit(ch)) 
	{
		w |= ch == '-';
		ch = getchar();
	}
    while(isdigit(ch)) 
	{
		ret = (ret << 3) + (ret << 1) + (ch ^ 48);
		ch = getchar();
	}
    return w ? -ret : ret;
}
inline void write(int ret)
{
     if(ret < 0)
     {
     	putchar('-');
		ret = -ret;
	 }	
     if(ret > 9) 
	 	write(ret / 10);
     putchar(ret % 10 + '0');
}
void bj(int x,int y,int z)
{
    ne[++tot] = last[x];
    last[x] = tot;
    to[tot] = y;
    v[tot] = z;
}
bool cmp(ddx x,ddx y)
{
    return x.h < y.h;
}
int spfa(int x)
{
    memset(bz,true,sizeof(bz));
    fill(dis,dis + 1 + n,1200000000);
    memset(num,0,sizeof(num));
    int head = 0,tail = 1,g;
    dis[x] = 0;
    d[1] = x;
    while(head < tail)
    {
        g = d[++head];
        bz[g] = true;
        for(register long long i = last[g];i;i = ne[i])
        {
            long long j = to[i];
            if(dis[j] > dis[g] + v[i])
            {
                dis[j] = dis[g] + v[i];
                if(bz[j])
                {
                    bz[j] = false;
                    d[++tail] = j;
                    if(++num[j] > n) 
						return -1;
                }
            }
        }
    }
    return 0;
}
int main()
{
    T = read();
    while(T--)
    {
        pp++; 
        n = read();
        dd = read();
        tot = 0;
        memset(last,0,sizeof(last));
        memset(ne,0,sizeof(ne));
        memset(to,0,sizeof(to));
        memset(v,0,sizeof(v));
        for(int i = 1;i <= n;i++)
        {
            a[i].h = read();
            a[i].p = i;
            bj(i,i - 1,-1);
        }
        sort(a + 1,a + 1 + n,cmp);
        for(int i = 1;i <= n - 1;i++)
        {
            if(a[i].p < a[i + 1].p)
                bj(a[i].p,a[i + 1].p,dd);
            else
                bj(a[i + 1].p,a[i].p,dd);
        }
        int e,k;
        if(a[1].p < a[n].p)
        {
            k = spfa(a[1].p);
            e = a[n].p;
        }
        else
        {
            k = spfa(a[n].p);
            e = a[1].p;
        }
        if(k == -1) 
        {
        	write(-1);
        	puts("");
		}
        else
        {
        	write(dis[e]);
        	puts("");
		}
    } 
}

4.游戏

题目:

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

输入:

一行,一个整数n

输出:

一行,一个整数m

数据范围:

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

思路:

由于一次性提出m个问题,然后得到回答,所以只能通过问题来确定最终可能的所有情况。考虑一个数的质因子分解,n=2^X1*3^X2*5^X3....即要确定所有质数可能出现的次数,所以答案为所有质数的幂次<=n的个数

Code:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cctype>
#include<cmath>
using namespace std;
bool f[100010];
long long w;
int n,ans;
inline int read()
{
    int ret = 0,w = 0; 
	char ch = 0;
    while(!isdigit(ch)) 
	{
		w |= ch == '-';
		ch = getchar();
	}
    while(isdigit(ch)) 
	{
		ret = (ret << 3) + (ret << 1) + (ch ^ 48);
		ch = getchar();
	}
    return w ? -ret : ret;
}
inline void write(int ret)
{
     if(ret < 0)
     {
     	putchar('-');
		ret = -ret;
	 }	
     if(ret > 9) 
	 	write(ret / 10);
     putchar(ret % 10 + '0');
}
int main()
{
	//freopen("game.in","r",stdin);
	//freopen("game.out","w",stdout);
	n = read();
	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;
			}
		}
	write(ans);
}


猜你喜欢

转载自blog.csdn.net/qq_40155097/article/details/81020379