20180530模拟赛T2——绀碧之棺

题目背景Background

qiancl 得到了一张藏宝图,上面写了一道谜题。

题目描述 Description

定义\(F(n)\)为 n 在十进制下各个数位的平方和,求区间\([a,b]\)中有多少\(n\)满足\(k\times F(n) = n\)。

输入描述 (coffin.in) Input Description

一行三个正整数\(k,a,b\)。

输出描述 (coffin.out) Output Description

一行一个整数表示满足条件的\(n\)的个数。

样例输入Sample Input

51 5000 10000

样例输出 Sample Output

3

数据范围及提示 Data Size & Hint

测试数据 对应数据范围
其中12个测试点 \(1\le k,a,b\le 105\)
其中6个测试点 \(233\le k\le 250\),且\(1\le a,b\le10^8\)
剩下32个测试点 \(1\le k,a,b\le 10^{18}\)

样例中满足的\(3\)个\(n\)分别是\(7293,7854,7905\)。

题解

开始被\(10^{18}\)的数据范围给吓到了,%你赛结束后听说有人打了数位dp(代码看这里)。orz

然而正解是枚举??。

开始我没想那么多,就打了个普通的枚举,然后开始考虑优化。

首先,不难发现\(k\mid n\),于是我们就可以让\(n\) k个k个地加。

然后我们就考虑一下缩小枚举区间:

首先\(n\)是要求的,无法考虑在此方向拓展;

\(k\)于是我们就想到\(F(n)\),考虑到\(n \le 10^{18}\),又因为题目中明确说明“在十进制下”,于是我们就不难发现\(F(n)\le 9^2\times 18 = 1458\)(每一位都取\(9\))。又因为我们是\(k\)位\(k\)位枚举的,所以我们最多只需枚举\(1458\)次。

注意开long long

代码

#include <fstream>
#include <algorithm>

using namespace std;

ifstream fin("coffin.in");
ofstream fout("coffin.out");

typedef long long LL;

LL a, b, k;

const int sqr[] = {0, 1, 4, 9, 16, 25, 36, 49, 64, 81};
const int kk = 81*18;

inline LL F(LL x)
{
    LL ans = 0;
    while(x)
    {
        ans += sqr[x%10];
        x /= 10;
    }
    return ans;
}

inline bool check(LL n)
{
    return F(n)*k == n;
}

int main()
{
    int ans = 0;
    fin >> k >> a >> b;
    if(a == b)
    {
        fout << check(a);
        return 0;
    }
    LL l = (a%k) ? ((a/k)+1)*k : a;
    LL r = min((kk*k), b);
    for(LL i = l; i <= r; i += k)
        if(check(i))
            ans++;
    fout << ans << '\n';
    return 0;
}

原文地址:https://www.cnblogs.com/pfypfy/p/9112841.html

时间: 2024-10-02 08:10:42

20180530模拟赛T2——绀碧之棺的相关文章

2017 9 11 noip模拟赛T2

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=205; int map[N][N]; int d[N],tag[N],book[N],f[N]; int n,m; void work(int x) { memset(d,63,sizeof(d)); memset(book,0,sizeof(book)); memset(f,0,sizeof(

[10.4模拟赛]T2

T2 Description 现有一个\(n\)个点,\(m\)条无向边的图.要求求出从编号为\(1\)的点到编号为\(n\)的点经过的边的边权的绝对值之和最小的路径.特别的,每经过一条边,图上所有边的边权就会改变,若原边权为x,新的边权是\(\frac{1}{1-x}\). 答案保留3位小数 Input 第一行两个整数\(m\),\(n\),表示点数和边数. 接下来\(m\)行,每行三个整数\(u\),\(v\),\(x\),表示有一条连接\(u\),\(v\),边权位\(x\). Outpu

字符串模拟赛T2

// source code from laekov for c0x17 #define PRID "fkqh" #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 200009; int n, l[maxn], q[maxn], vx[maxn], vy[maxn]; char a[maxn]; void ma

20161022 NOIP模拟赛 T2 解题报告

旅行者问题 [问题描述] lahub是一个旅行者的粉丝,他想成为一个真正的旅行者,所以他计划开始一段旅行.lahub想去参观n个目的地(都在一条直道上).lahub在起点开始他的旅行.第i个目的地和起点的距离为ai千米(ai为非负整数).不存在两个目的地和起点的距离相同. 从第i个目的地走到第j个目的地所走的路程为 |ai-aj|千米.我们把参观n个目的地的顺序称作一次“旅行”.lahub可以参观他想要参观的任意顺序,但是每个目的地有且只能被参观一次(参观顺序为n的排列). lahub把所有可能

11.12 模拟赛T2 冒泡排序图

[问题描述] 有一段使用冒泡排序产生一张图的伪代码如下:function bubbleSortGraph(n, a[]): graph = emptyGraph() repeat swapped = false for i = 1 to n - 1:  if a[i] > a[i + 1]: graph.addEdge(a[i], a[i + 1]) swap(a[i], a[i + 1]) swapped = true until not swapped return graph函数的输入为长

洛谷 U361 序列操作(NOIP模拟赛T2)

题目链接:https://www.luogu.org/problem/show?pid=U361 题目背景 夏令营 题目描述 小B有一个整数序列a[1..N],初始时序列中所有元素均为0.他会在序列上进行下面两种操作,操作共M个: A l r x:将a[l..r]均加上x. Q l r:询问a[l..r]中的最大值. 输入输出格式 输入格式: 第一行,两个整数N, M. 接下来的M行,每行一个操作. 输出格式: 设询问操作有T个,则输出T行,每行一个整数,表示询问操作对应的答案. 输入输出样例

2017/9/3模拟赛T2

题解:由于题目已经提示我们这是个单峰函数,所以很容易想到三分法,所以我们就枚举中位数,为保证平均数最大,左右两侧都从右往左取数. 代码如下: 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #define MN 100005 5 using namespace std; 6 int n,a[MN],maxl,l,r,lm,rm; 7 long long sum[MN]; 8 double a

2017 9 27 模拟赛 T2

原题题意:给出一个集合S,现满足以下关系: 实际题意:求32的n次方(这...)

2018.02.12 noip模拟赛T2(未完待续)

二兵的赌注 Description游戏中,二兵要进入了一家奇怪的赌场.赌场中有n个庄家,每个庄家都可以猜大猜小,猜一次一元钱.每一次开彩前,你都可以到任意个庄家那里下赌注.如果开彩结果是大,你就可以得到你之前猜大的庄家相应的ai元钱.如果开彩结果是小,你就可以得到你之前猜小的庄家相应的bi元钱.你可以在同一个庄家那里既猜大又猜小,(这样是两块钱),也可以什么都不猜(这样不用钱).问怎么样下注,才能赢得最多的有保障的钱.有保障的钱指不管开彩结果是大是小,你都能够赢得相应的钱.你能帮助他计算这个值吗