A. Madoka and Strange Thoughts
标签:数学
题意:
- 给出一个n,求1到n中有多少组(a,b)使得 lcm(a,b)/gcd(a,b)>=3
思路:
众所周知lcm = a*b/gcd
,把式子转化为 a*b >= 3*gcd * gcd
,这样做一点用都没有
实际上这题我们可以枚举一下情况
我们令 tmp = gcd(a,b)
情况1: a = b = tmp
情况2: a = 2*tmp, b = tmp
或者 a = tmp, b =2* tmp
情况3: a = 3*tmp, b = tmp
或者 a = tmp, b =3* tmp
除此之外就没有符合的情况了
写的时候被卡了十分钟,我太菜了
代码:
#define fst std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout << std::fixed << std::setprecision(20)
#define le "\n"
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 50;
const int mod = 1e9 + 7;
void solve() {
long long n;
cin >> n;
cout << n + 2 * (n / 2 + n / 3) << le;//对应以上三种情况
}
int main() {
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
B. Madoka and Underground Competitions
标签:构造模拟
题意:
- 有一n*n大小的矩阵,让你用
.
和X
去填充里面的方格 - 要求矩阵中每 1 * k 和 k * 1的区域内至少含有一个X
- 给出r和c,要求坐标(r , c)方格必须为X
- 要求使用尽可能少的X,输出符合要求的矩阵
思路:
题目明确n为k的倍数,我们首先思考一个k*k的矩阵,只要一条对角线上为X即可
然后构造大矩阵
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (i % k == j % k)
cout << 'X';
else
cout << '.';
}
cout << le;
再来思考r,c,注意到我们原本式子中当i=k时输出x,此时i和j的偏差为0
我们对r和c取模比较,r%k与c%k的偏差多少 i和j的偏差就多少
代码:
#define fst std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout << std::fixed << std::setprecision(20)
#define le "\n"
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 50;
const int mod = 1e9 + 7;
void solve() {
int n, k, r, c;
cin >> n >> k >> r >> c;
int dif = (r % k - c % k + k) % k;//两者的偏差
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if ((i - dif + k) % k == j % k)
cout << 'X';
else
cout << '.';
}
cout << le;
}
}
int main() {
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
C. Madoka and Formal Statement
标签:贪心 思维
题意:
- 有长度为n的数列a和b
- 只要a[i]<=a[(i+1)%n],就可以a[i]进行加1操作
- 问能否通过操作得到a = b
思路:
依旧分情况讨论
- a[i] = b[i] 不用操作,一定可行
- a[i] > b[i] 寄
- a[i] < b[i] ,a[i]的理论最大值为b[(i+1)%n]+1,若b[i]大于理论最大值,则不可行
代码:
#define fst std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout << std::fixed << std::setprecision(20)
#define le "\n"
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 50;
const int mod = 1e9 + 7;
void solve() {
int n;
cin >> n;
vector<int> a(n), b(n);
for (int i = 0; i < n; i++) cin >> a[i];
for (int i = 0; i < n; i++) cin >> b[i];
bool f = 1;
for (int i = 0; i < n; i++) {
if (a[i] > b[i]) f = 0;//情况二
if (a[i] < b[i] && b[i] > b[(i + 1) % n] + 1) f = 0;//情况三
}
if (f)
cout << "YES" << le;
else
cout << "NO" << le;
}
int main() {
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
D. Madoka and The Corruption Scheme
标签:博弈 二叉树 排列组合
题意:
- 2n个人打OSU(音游,太难玩了)
- 进行n轮比赛,每轮比赛中两两对战
- 比赛特别黑,Madoka可以决定对战中谁胜谁负,并且第一轮可以重新排序比赛选手
- 主办方有k次操作机会,每次操作可反转本轮比赛结果,即在Madoca判完本轮每个选手的胜负之后反转结果
- 主办方希望最终胜利者的编号越大越好,Madoka希望最终胜利者的编号越小越好
- 双方均采取最优策略 输出可能的最终胜利者的编号
思路:
看了其他人题解才知道,这题居然是排列组合,原理也是非常巧妙的
画个比较简陋的图来解释一下
我们将
我们将左边定义为胜利边,右边为失败边,每次将失败反转需要消耗一次操作
定义根节点权值为0,然后以上述规则来画,得到每个节点的权值
考虑贪心的思想,我们应该将大的数字放到大的权值上面,比如当n=3时,我们将
23 放到权值为3的地方去,表示需要三次操作才能得到
观察第四行 我们发现0 1 2 3 4各点的数量符合杨辉三角的分布
因此答案就等于2n 减去全部权值大于k的数的数量
代码:
#define fst std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout << std::fixed << std::setprecision(20)
#define le "\n"
#define ll long long
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 50;
const int mod = 1e9 + 7;
ll fact[N], inv[N];
ll qpow(ll a, ll b) {
ll res = 1;
while (b) {
if (b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
ll C(int a, int b) { return (fact[b] * inv[a] % mod) * inv[b - a] % mod; }
ll qsm(int a, int b) {
ll base = a, res = 1;
while (b) {
if (b & 1) res = res * base % mod;
base = base * base % mod;
b >>= 1;
}
return res;
}
int main() {
int n, k;
cin >> n >> k;
fact[0] = inv[0] = 1;
for (int i = 1; i <= n; i++) fact[i] = fact[i - 1] * i % mod;
inv[n] = qpow(fact[n], mod - 2) % mod;
for (ll i = n - 1; i >= 1; i--) inv[i] = inv[i + 1] * (i + 1) % mod;
ll ans = qsm(2, n);
if (k >= n) {
cout << ans << le;
} else {
for (int i = k + 1; i <= n; i++) {
ans = ((ans - C(i, n)) % mod + mod) % mod;
}
cout << ans << endl;
}
return 0;
}