题目描述
猫猫 Iris 又在玩 oql 的键盘了。
在 T 天的时间里,每一天 Iris 会在玩 oql 键盘的时候敲下若干个字符,而这些字符恰好全都是 0 ∼ 9 0∼9 0∼9 这 10 10 10 个阿拉伯数字。经过统计,数字 i i i 有 a i a_i ai个。oql 每天可能会给 Iris 喂一定数量的猫粮。他决定,在这 ∑ i = 0 9 a i \sum^9_{i=0}a_i ∑i=09ai 个数字里选择 m m m 个,经过重新排列后形成一个十进制下 m m m 位、且不包含前导 0 的非负整数 x,然后 oql 将在这天给 Iris 投喂 x x x 克的猫粮。
然而,Iris 还是一只小猫,不宜食用太多的猫粮。因此 oql 想让这个数字尽可能小。请你帮助 Iris 计算出她每天能得到多少猫粮。由于答案可能很大,你只需要输出答案对 1 0 9 + 7 10^9+7 109+7 取模的结果。请注意,你需要输出的是最小答案模 1 0 9 + 7 10^9+7 109+7 后的结果,而不是 x x x m o d mod mod 1 0 9 + 7 10^9+7 109+7 的最小值。
Input
第一行一个正整数 T ( 1 ≤ T ≤ 1 0 4 ) T (1≤T≤10^4) T(1≤T≤104),表示天数。
第 2 ∼ ( T + 1 ) 2∼(T+1) 2∼(T+1) 行,每行 11 11 11 个由空格分隔的非负整数 m , a 0 , a 1 , ⋯ , a 9 ( 1 ≤ m ≤ 1 0 9 , 0 ≤ a i ≤ 1 0 9 ) m,a_0,a_1,⋯,a_9(1≤m≤10^9,0≤a_i≤10^9) m,a0,a1,⋯,a9(1≤m≤109,0≤ai≤109),表示第 i i i 天的情况。
数据保证有解,即至少能形成一个 m m m 位不包含前导 0 0 0 的非负整数。
Output
对于每一天,输出一行一个整数,表示 Iris 这一天能得到的猫粮对 1 0 9 + 7 10^9+7 109+7 取模后的结果。
Sample Input 1
3
3 1 0 0 0 3 0 0 0 0 0
1 2 0 0 0 0 0 0 0 0 0
4 0 1 1 1 3 0 0 0 0 0
Sample Output 1
404
0
1234
解题思路
很简单的一个贪心,因为不能有前导零,所以可以先从 1 ∼ 9 1 \sim 9 1∼9 中拿出一个最小的数作为第一个数,之后就可以从 0 ∼ 9 0 \sim 9 0∼9 从小往大依次选择 m − 1 m-1 m−1 个数即可
接下来的问题就是高精度取余了,由同余定理可知:
假设一个数 x = a b c d = a ∗ 1000 + b ∗ 100 + c ∗ 10 + d x=abcd=a*1000+b*100+c*10+d x=abcd=a∗1000+b∗100+c∗10+d
= ( ( ( a ∗ 10 + b ) ∗ 10 + c ) ∗ 10 + d ) =(((a*10+b)*10+c)*10+d) =(((a∗10+b)∗10+c)∗10+d)
那么 x % p = ( ( ( ( ( ( a % p ) ∗ 10 + b ) % p ) ∗ 10 + c ) % p ) ∗ 10 + d ) % p x\%p=((((((a\%p)*10+b)\%p)*10+c)\%p)*10+d)\%p x%p=((((((a%p)∗10+b)%p)∗10+c)%p)∗10+d)%p
所以,对于一个数字字符串 S S S,求它取余 p p p,就是如下实现
long long res = 0;
for (char c : S)
{
int x = c - '0';
res = (res * 10 + x) % p;
}
return res;
那么,如何计算答案呢?
假设 a = x x x x x x a=xxxxxx a=xxxxxx,如何求 b = x x x x x x y y y y y y y y m o d p b=xxxxxxyyyyyyyy\,mod\,p b=xxxxxxyyyyyyyymodp 的值
我们可得到下列式子
b = a ∗ 1 0 8 + y y y y y y y y b = a * 10^8 + yyyyyyyy b=a∗108+yyyyyyyy
b % p = ( a ∗ 1 0 8 % p + y y y y y y y y % p ) % p b\%p=(a*10^8\%p+yyyyyyyy\%p)\%p b%p=(a∗108%p+yyyyyyyy%p)%p
现在,问题都解决了,我们只需要预处理出一个数组 c n t cnt cnt, c n t [ i ] cnt[i] cnt[i]表示长度为 i i i 的全 1 1 1 数字 m o d 1 0 9 + 7 mod\,10^9+7 mod109+7 的值,上面的式子就可以得到以下变换:
b % p = ( a ∗ 1 0 8 % p + ( 11111111 ∗ y ) % p ) % p b\%p=(a*10^8\%p+(11111111*y)\%p)\%p b%p=(a∗108%p+(11111111∗y)%p)%p
最后,注意特判 m = 1 m=1 m=1 且 a [ 0 ] ≥ 1 a[0] \geq 1 a[0]≥1时,答案为 0 0 0
实现代码
#pragma GCC optimize(3, "Ofast", "inline")
#include<bits/stdc++.h>
#define int long long
#define x first
#define y second
#define debug(x) cerr << #x" = " << x << '\n';
using namespace std;
const int mod = 1e9 + 7;
int cnt[10000010];
int qmi(int a, int b)
{
int res = 1;
while (b)
{
if (b & 1) res = res * a % mod;
b >>= 1;
a = a * a % mod;
}
return res;
}
void init()
{
for (int i = 1; i <= 10000000; i++) // 预处理出10^7个1 % p的值
{
cnt[i] = cnt[i - 1] * 10 + 1;
cnt[i] %= mod;
}
}
void solve()
{
int m;
cin >> m;
vector<int> a(10);
for (int i = 0; i < 10; i++) cin >> a[i];
int res = 0;
if (m == 1 && a[0]) return cout << 0 << '\n', void();
for (int i = 0; i < 10; i++)
{
if (a[i] && i)
{
res = res * 10 + i;
res %= mod;
m --;
a[i] --;
break;
}
}
// 如果发现只能取0,则直接输出0
if (res == 0) return cout << 0 << '\n', void();
for (int i = 0; i < 10; i++)
{
int x = min(m, a[i]);
m -= x;
while (x >= 10000000)
{
res = (res * qmi(10, 10000000) % mod + cnt[10000000] * i % mod) % mod;
x -= 10000000;
}
if (x) res = (res * qmi(10, x) % mod + cnt[x] * i % mod) % mod;
}
cout << res << '\n';
}
signed main()
{
// freopen("Sample.in", "r", stdin);
ios::sync_with_stdio(false);
cin.tie(nullptr);
init();
int T = 1;
cin >> T;
while (T--) solve();
return 0;
}