T1 临时换题(huan)
1.1 题目描述
现在都已经八点半了, pufanyi 现在因为 std 出锅很自闭,于是决定临时换题。原
来的 Day1T1 将会被移到 Day2,现在你看到的是原来的 Day2T1。
本题均使用十进制计数。
和一般的女孩子一样,小小迪喜欢教钧钧数数。
给定两个正整数 l 和 r,对于任意 x,满足 l ≤ x ≤ r,把 x 的所有约数全部写下
来。对于每个写下来的数,只保留最高位的那个数码。求 [1, 9] 中每个数码出现的次数。
这里的约数是指:对于正整数 y,如果正整数 x 使得存在正整数 k 有 kx = y, x 是
y 的约数。
1.2 输入输出格式
1.2.1 输入格式
从文件 huan.in 中读入数据。
输入一行两个正整数 l 和 r。
1.2.2 输出格式
输出到文件 huan.out 中。
输出一行 9 个非负整数,每两个数字之间用一个空格分开,第 i 个数表示数码 i 出
现的次数。
1.3 样例
1.3.1 样例 1 输入
1 4
1.3.2 样例 1 输出
4 2 1 1 0 0 0 0 0
1.3.3 样例 1 解释
数字 约数 最高位
1 1 1
2 1, 2 1, 2
3 1, 3 1, 3
4 1, 2, 4 1, 2, 4
1.3.4 样例 2 输入
233 238
1.3.5 样例 2 输出
13 10 4 2 2 1 3 0 1
1.3.6 样例 2 解释
数字 约数 最高位
233 1, 233 1, 2
234 1, 2, 3, 6, 9, 13, 18, 1, 2, 3, 6, 9, 1, 1, 2, 3, 7, 1, 2
26, 39, 78, 117, 234
235 1, 5, 47, 235 1, 5, 4, 2
236 1, 2, 4, 59, 118, 236 1, 2, 4, 5, 1, 2
237 1, 3, 79, 237 1, 3, 7, 2
238 1, 2, 7, 14, 17, 1, 2, 7, 1, 1, 3, 1, 2
34, 119, 238
1.4 数据范围与提示
本题共 10 个测试点,每个测试点 10 分。
对于所有测试点,均有 l ≤ r。
每个测试点的具体限制见下表。
测试点编号 r 特殊性质
1 ∼ 2 ≤ 10000 无
3 ∼ 5 ≤ 107
6 ∼ 7 ≤ 109 r − l ≤ 1000
8 ∼ 10 无
本题答案有 32 位整型溢出风险,故统计答案时请务必使用 64 位整型。
思路:
由题意可得 ans[getmax(i)]+=n/i
暴力的话1e7可以过直接50分,1e9会TLE
因为其实只需要考虑最高位对答案的贡献,并且我们发现在某一段区间内,对答案的贡献是一样的
比如(50,100]=1
而这个区间为 (n/k+1,n/k],贡献值为k;
枚举首位遍历不同的区间
1->(10,19)->(100-199)
再在这个区间内根据 (n/k+1,n/k]划分区间
最后答案累加a(当前区间的值得贡献)*d(区间长度)
例:100
30-39的区间
a=3,区间33 (30,33)100/34=2,100/2=50,50和39进行比较(34,39)
所以划分为(30,33)(34,39)
1 #include <bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 inline int read(){ 5 int s=0,w=1; 6 char ch=getchar(); 7 while(ch<'0'||ch>'9'){if(ch=='-')w=-1,ch=getchar();} 8 while(ch>='0'&&ch<='9'){s=s*10+ch-'0',ch=getchar();} 9 return s*w; 10 } 11 ll ans[2][10],l,r; 12 inline void solve(int tot,int n){ 13 for(int i=1;i<=9;i++){ 14 for(int j=1;j*i<=n;j*=10){ 15 ll d,l=1ll*i*j,r=min(1ll*i*j+j-1,(ll)n);//d区间长度,l,r左右边界 16 for(ll k=l;k<=r;k+=d){ 17 ll a=n/k,b=n%k;//a为区间的统一贡献值,b=n-a*k; 18 d=1+min(b/a,r-k);//b/a=n/a-k,(n/a)即为断点的值,r-k防止越界 19 ans[tot][i]+=a*d; 20 } 21 } 22 } 23 } 24 int main(){ 25 freopen("huan.in", "r", stdin); 26 freopen("huan.out", "w", stdout); 27 scanf("%d%d", &l, &r); 28 solve(0, r), solve(1, l - 1); 29 for (int i = 1; i <= 9; ++i) { 30 printf("%lld ", ans[0][i] - ans[1][i]); 31 } 32 return 0; 33 }