Loading

「解题报告」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\)种选择,故方案数为

\[(v-n)^{n-\frac{v}{2}} \]

剩下的部分是一个完全图,令\(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;
}
posted @ 2023-10-29 19:13  yi_fan0305  阅读(18)  评论(0编辑  收藏  举报