「解题报告」2023-10-29 模拟赛
魔法串
(magic.cpp/c/pas)magic.in magic.out
【问题描述】
小 \(N\) 最近在沉迷数学问题。
对于一个数字串 \(S\),如果可以将它划分成两个数字 \(A\)、\(B\),满足:
1、 。
2、 \(A\)、\(B\) 均不包含前导 \(0\)。
3、 \(B\) 是 \(A\) 的倍数,且\(\dfrac{B}{A}\)是完全立方数。
那么小 \(N\) 就认为该划分是一个“好划分”。 如对于数字串“\(11297\)”,(\(11\), \(297\))就是一个“好划分”。
如果一个数字串 \(S\) 至少有两个“好划分”,那么小 \(N\) 就认为 \(S\) 是一个“魔法串”。如数字串“\(1335702375\)”就是一个“魔法串”,其“好划分”有(\(1\), \(335702375\))和(\(133\),\(5702375\))。
现在给定正整数 \(N\),小 \(N\) 需要你帮她求出一个长度恰好为 \(N\) 的“魔法串”\(S\),如果无解请输出“QwQ”(不带引号)。
【输入】
一行一个正整数 \(N\)。
【输出】
一行一个长度恰好为 \(N\) 的“魔法串”\(S\), 如果无解请输出“QwQ”(不带引号) 。
【输入输出样例】
19
【输出样例】
1124784124392112128
【数据范围】
对于 \(30\%\) 的数据: \(1 \le N \le 10\)。
对于 \(50\%\) 的数据: \(1 \le N \le 35\)。
对于 \(100\%\) 的数据: \(1 \le N \le 100\)。
当 \(N \le 4\) 时无解。
如果数字串 \(S\) 是一个魔法串,那么向 \(S\) 后面添加 “\(000\)” 后得到的新串也是一个魔法串。那所以只需要求出 \(N = 5、6、7\) 时的可行解,就可以推广到所有情况。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, a, b, c) for (int i = (a); i <= (b); i += (c))
#define per(i, a, b, c) for (int i = (a); i >= (b); i -= (c))
#define orz puts("sym, cjx, gjh AK IOI!!!");
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? -x : x;
}
const int N = 40;
int n, tmpn;
int num[N];
bool vis[10000005];
void work() {
int cnt = 0;
rep (i, 2, tmpn, 1) {
bool fg = 0;
ll res1 = 0, res2 = 0;
rep (j, 1, i - 1, 1) {
res1 = res1 * 10 + num[j];
if (!res1) {
fg = 1;
break ;
}
}
if (fg) continue ;
rep (j, i, tmpn, 1) {
res2 = res2 * 10 + num[j];
if (!res2) {
fg = 1;
break ;
}
}
if (fg) continue ;
if (res2 % res1 == 0) {
ll tmp = res2 / res1;
if (!vis[tmp]) continue ;
++ cnt;
}
}
if (cnt < 2) return ;
rep (j, 1, tmpn, 1) {
printf("%d", num[j]);
}
rep (j, tmpn + 1, n, 1) {
printf("0");
}
putchar('\n');
exit(0);
}
void dfs(int u) {
if (u > tmpn) {
work();
return ;
}
rep (i, 0, 9, 1) {
if (i == 0 && u == 1) {
continue ;
}
num[u] = i;
dfs(u + 1);
}
}
int main() {
freopen("magic.in", "r", stdin);
freopen("magic.out", "w", stdout);
for (ll i = 1; i <= 1000; ++ i) {
if (i * i * i > 10000000) break ;
vis[i * i * i] = 1;
}
n = read<int>();
int tmp = n - 4;
tmp %= 3;
switch(tmp) {
case 0:
tmpn = 7;
break ;
case 1:
tmpn = 5;
break ;
case 2:
tmpn = 6;
break ;
}
dfs(1);
puts("QwQ");
fclose(stdin);
fclose(stdout);
return 0;
}
配对
(pair.cpp/c/pas)pair.in pair.out
【问题描述】
有 \(1~n\) 一共 \(n\) 个数,\(n\) 为偶数。小 \(Q\) 要把这 \(n\) 个数随机地两两配对。令每一对的权值为它们两个数的和。小 \(Q\) 想要知道这 \(n\) 对里最大的权值的期望是多少。请输出答案对 \(10^9+7\) 取模的值。
【输入】
一行一个正整数 \(N\)。
【输出】
一行一个整数,表示答案对 \(10^9+7\) 取模的值。
【输入样例】
4
【输出样例】
6
【数据范围】
对于 \(20\%\) 的数据: \(1 \le N \le 10\)。
对于 \(40\%\) 的数据: \(1 \le N \le 2000\)。
对于 \(100%\) 的数据: \(1 \le N \le 500000\)。
考虑枚举答案是否\(\ge v\)
转化成答案是否\(\le v\)
把\(1-n\)分成两部分,一部分是\(>\frac{v}{2}\)的,一部分是\(\le \frac{v}{2}\)的。
显然\(>\frac{v}{2}\)的只能和\(\le\frac{v}{2}\)的匹配。
我们从大到小枚举\(>\frac{v}{2}\)的部分,每次都有\(v-n\)种选择,故方案数为
剩下的部分是一个完全图,令\(f(x)\)为\(x\)个点的方案数,\(f(x)\)为\(1 \times 3 \times 5 \times \cdots \times (x/2)\)
预处理阶乘后可以\(O(nlogn)\)进行计算。
// The code was written by yifan, and yifan is neutral!!!
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define bug puts("NOIP rp ++!");
#define rep(i, a, b, c) for (int i = (a); i <= (b); i += (c))
#define per(i, a, b, c) for (int i = (a); i >= (b); i -= (c))
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
template<typename T>
void write(T x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x > 9) {
write(x / 10);
}
putchar(x % 10 + '0');
}
template<typename T>
void print(T x, char c) {
write(x);
putchar(c);
}
const int N = 5e5 + 5;
const int mod = 1e9 + 7;
ll n;
ll inv[N], pri[N];
ll qpow(ll x, ll y) {
ll ret = 1;
while (y) {
if (y & 1) {
ret = ret * x % mod;
}
x = x * x % mod;
y >>= 1;
}
return ret;
}
int main() {
freopen("pair.in", "r", stdin);
freopen("pair.out", "w", stdout);
n = read<int>();
inv[0] = pri[0] = 1;
rep (i, 1, n / 2, 1) {
pri[i] = pri[i - 1] * (2 * i - 1) % mod;
}
inv[n / 2] = qpow(pri[n / 2], mod - 2) % mod;
per (i, n / 2 - 1, 1, 1) {
inv[i] = inv[i + 1] * (2 * i - 1) % mod;
}
ll ans = 0, las = 0;
rep (v, n + 1, 2 * n - 1, 1) {
int k = n - v / 2;
ll z = qpow(v - n, k) % mod * pri[v / 2 - n / 2] % mod;
ans = (ans + 1ll * v * (((z - las) % mod + mod) % mod) % mod) % mod;
las = z;
}
printf("%lld\n", (ans * inv[n / 2]) % mod);
return 0;
}
幸运数
(lucky.cpp/c/pas)lucky.in lucky.out
【问题描述】
对于任意两个非零整数 \(x\),\(y\),若整数 \(d\) 能同时被 \(x\) 和 \(y\) 整除,则称 \(d\) 为 \(x\) 与 \(y\) 的公约数。定义 \(x\) 与 \(y\) 的最大公约数 \(\gcd(x, y)\) 为 \(x\) 与 \(y\) 的最大的公约数。
如 \(\gcd(6, 9) = 3, \gcd(12, 16) = 4, \gcd(25, 32) = 1\),等等。
这里,我们定义什么是幸运数:
对于一个正整数 \(d\),我们使用 \(d_i\) 表示 \(d\) 在十进制表示下,按从低位到高位顺序的第 \(i\) 位数字。
设 \(F(d)\) 表示 \(d\) 的奇数位的数字之和,即 \(F(d) = d_1 + d_3 + d_5 + \cdots\);
设 \(G(d)\) 表示 \(d\) 的偶数位的数字之和,即 \(G(d) = d_2 + d_4 + d_6 + \cdots\);
若 \(F(d)\) 与 \(G(d)\) 均大于 \(0\),且 \(F(d)\) 与 \(G(d)\) 的最大公约数不超过 \(K\),则称 \(d\) 为幸运数。其中 \(K\) 是一个已知的常数。
举个例子来说,若 \(d = 641\),则 \(d_1 = 1, d_2 = 4, d_3 = 6, F(641) = 1 + 6 = 7,G(641) = 4\)。此时 \(F(d)\) 与 \(G(d)\) 的最大公约数即 \(\gcd(7, 4)\) 等于 \(1\)。则当 \(K\) 不小于 \(1\) 时 \(641\) 是幸运数。
小 \(M\) 请你回答下面的问题:
对于给定的 \(K\),在不小于 \(L\) 并且不超过 \(R\) 的所有整数中,有多少个数是幸运数?
注意,输入文件包含多组测试数据。
【输入文件】
第一行包含一个整数 \(T\),表示有 \(T\) 组测试数据。
接下来 \(T\) 行,每行包含三个整数 \(K、L、R\),表示一次询问。
【输出文件】
输出 \(T\) 行,每行一个整数,依次表示每组测试数据的答案。
【输入样例】
5
1 1 10
2 28 34
100 987654321 987654321
1 1 50000
1 50001 100000
【输出样例】
0
5
1
30298
30309
【样例解释】
\(K = 1\) 时,\(1\) 到 \(10\) 之间不存在幸运数。
\(K = 2\) 时,\(28\) 到 \(34\) 之间的幸运数有 \(28、29、31、32、34\),共 \(5\) 个。
\(K = 100\) 时,\(987654321\) 是幸运数。
\(K = 1\) 时,\(1\) 到 \(50000\) 之间的幸运数有 \(30298\) 个,\(50001\) 到 \(100000\) 之间的幸运数有 \(30309\) 个。
【数据规模和约定】
对于 \(10\%\) 的数据:\(1 \le L \le R \le 10^3\)。
另有 \(10\%\) 的数据:\(1 \le L \le R \le 10^7,1 \le K, T \le 10\)。
另有 \(10\%\) 的数据:\(1 \le L \le R \le 10^9,K = 1,1 \le T \le 10\)。
对于 \(60\%\) 的数据:\(1 \le L \le R \le 10^{12},1 \le K, T \le 10^2\)。
对于 \(100\%\) 的数据:\(1 \le L \le R \le 10^{18}, 1 \le K \le 10^2,1 \le T \le 1000\)。
60 pts:
设 \(f(i, sum1, sum2)\) 为在第 \(i\) 位,奇数位上的数的和为 \(sum1\),偶数位上的数的和为 \(sum2\),进行数位 DP。
// The code was written by yifan, and yifan is neutral!!!
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define bug puts("NOIP rp ++!");
#define rep(i, a, b, c) for (int i = (a); i <= (b); i += (c))
#define per(i, a, b, c) for (int i = (a); i >= (b); i -= (c))
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
template<typename T>
void write(T x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x > 9) {
write(x / 10);
}
putchar(x % 10 + '0');
}
template<typename T>
void print(T x, char c) {
write(x);
putchar(c);
}
int T;
ll k, l, r;
int a[100];
ll f[25][180][180];
ll dfs(int dig, int lim, ll sum1, ll sum2) {
if (dig == 0) {
if (sum1 && sum2 && __gcd(sum1, sum2) <= k) {
return 1;
}
return 0;
}
if ((!lim) && (~f[dig][sum1][sum2])) {
return f[dig][sum1][sum2];
}
int num = lim ? a[dig] : 9;
ll ans = 0;
rep (i, 0, num, 1) {
ll tmp1 = sum1, tmp2 = sum2;
if (dig & 1) {
tmp1 += i;
} else {
tmp2 += i;
}
ans += dfs(dig - 1, lim && i == a[dig], tmp1, tmp2);
}
if (!lim) {
f[dig][sum1][sum2] = ans;
}
return ans;
}
ll solve(ll n) {
int cnt = 0;
while (n) {
a[++ cnt] = n % 10;
n /= 10;
}
return dfs(cnt, 1, 0, 0);
}
void work() {
memset(f, -1, sizeof f);
k = read<ll>(), l = read<ll>(), r = read<ll>();
cout << solve(r) - solve(l - 1) << '\n';
}
int main() {
freopen("lucky.in", "r", stdin);
freopen("lucky.out", "w", stdout);
T = read<int>();
while (T --) {
work();
}
return 0;
}