报数[P7960]

题目

题目链接

报数游戏是一个广为流传的休闲小游戏。参加游戏的每个人要按一定顺序轮流报数,但如果下一个报的数是 77 的倍数,或十进制表示中含有数字 77,就必须跳过这个数,否则就输掉了游戏。

在一个风和日丽的下午,刚刚结束 SPC20nn 比赛的小 r 和小 z 闲得无聊玩起了这个报数游戏。但在只有两个人玩的情况下计算起来还是比较容易的,因此他们玩了很久也没分出胜负。此时小 z 灵光一闪,决定把这个游戏加强:任何一个十进制中含有数字 77 的数,它的所有倍数都不能报出来!

形式化地,设 𝑝(𝑥)p(x) 表示 𝑥x 的十进制表示中是否含有数字 77,若含有则 𝑝(𝑥)=1p(x)=1,否则 𝑝(𝑥)=0p(x)=0。则一个正整数 𝑥x 不能被报出,当且仅当存在正整数 𝑦y 和 𝑧z ,使得 𝑥=𝑦𝑧x=yz 且 𝑝(𝑦)=1p(y)=1。

例如,如果小 r 报出了 66 ,由于 77 不能报,所以小 z 下一个需要报 88;如果小 r 报出了 3333,则由于 34=17×234=17×2,35=7×535=7×5 都不能报,小 z 下一个需要报出 3636 ;如果小 r 报出了 6969,由于 70∼7970∼79 的数都含有 77,小 z 下一个需要报出 8080 才行。

现在小 r 的上一个数报出了 𝑥x,小 z 想快速算出他下一个数要报多少,不过他很快就发现这个游戏可比原版的游戏难算多了,于是他需要你的帮助。当然,如果小 r 报出的 x 本身是不能报出的,你也要快速反应过来小 r 输了才行。

由于小 r 和小 z 玩了很长时间游戏,你也需要回答小 z 的很多个问题。

Input

第一行,一个正整数 𝑇T 表示小 z 询问的数量。

接下来 𝑇T 行,每行一个正整数 𝑥x,表示这一次小 r 报出的数。

Output

输出共 𝑇T 行,每行一个整数,如果小 r 这一次报出的数是不能报出的,输出 −1−1,否则输出小 z 下一次报出的数是多少。

Sample 1

InputcopyOutputcopy
4
6
33
69
300
8
36
80
-1

Sample 2

InputcopyOutputcopy
5
90
99
106
114
169
92
100
109
-1
180

说明/提示

【样例解释 #1】

这一组样例的前 33 次询问在题目描述中已有解释。

对于第 44 次询问,由于 300=75×4300=75×4,而 7575 中含有 77 ,所以小 r 直接输掉了游戏。

【数据范围】

对于 10% 的数据,T≤10,x≤100。
对于 30% 的数据,T≤100,x≤1000。
对于 50% 的数据,T≤1000,x≤10000。
对于 70% 的数据,T≤10000,𝑥≤2×1e5。
对于 100% 的数据,1≤T≤2×1e5,1≤x≤1e7。

 

分析

本题是让我们判断一个数是否含有7或者是不是含有7的数的倍数,举例来说51虽然不含有7也不是7的倍数但51是17的倍数所以也不能输出51,我们可以先找一个范围内含有7的数,把这个数标记为不能输出后再把这个数范围内的所有倍数也标记为不能输出,遍历完范围内的全部数据后就可以得到数组a了,另外对于数组a的处理(数组a是当输入i时就直接输出a[i]),先判断i能否输出如果不行(也就是小r错误了)则令a[i]=-1如果可以输出(也就是小r是正确的)那就从i+1开始找 寻找能输出的数j再把这个数赋给a[i]。

坑点

因为题目数据时1e7如果先得到了not_put这个标记了不能输出元素的数组再通过输入时去寻找应该输出的值 那么会TLE,所以在得到not_put这个标记了不能输出元素的数组时就应该同步去寻找a[i]。

代码

#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
const int len=1e7+10,mod=1e9+7,N=-0x3fffffff;//祖传行 不必理会

int t,x,a[len];
bool not_put[len];//不能输出 也就是7的倍数或者含7的数的倍数

bool judge7(int x)//判断这个数里是否含有7
{
    string str=to_string(x);
    for(int i=0;i<str.size();i++)
    {
        if(str[i]=='7')
            return true;
    }
    return false;
}

void get_not_put()
{
    for(int i=7;i<len;i++)
    {
        if(judge7(i)||not_put[i])//如果含有7或者之前已经标记为不能输出则把这个数的倍数也标记为不能输出
        {
            not_put[i]=true;
        }
        {
            for(int j=1;i*j<len;j++)
                not_put[i*j]=true;
        }
    }
}

void get_puta()//得到a数组 a数组表示如果输入i那应该输出a[i]
{
    for(int i=0;i<len;i++)
    {
        if(not_put[i])//如果这个数本身就是不能输出的,也就是小r已经输了 就直接输出-1
            a[i]=-1;
        else
        {
            for(int j=i+1;j<len;j++)
            {
                if(!not_put[j])
                {
                    a[i]=j;//如果这个数不是不能输出的,那么就输出这个数
                    break;
                }
            }
        }
    }
}

int main()
{
    get_not_put();
    get_puta();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&x);
        printf("%d\n",a[x]);
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值