NOIP-R7
不是,这一次模拟赛这么抽象?
A
也是有了啊,第一题想的跟正解不一样,这里两个都讲。
自己:
很明显的,这个题一定和倍数之类的有关,于是一开始就想着直接在区间 \([l, r]\) 里开始跑筛,但是发现还是有重复或者说是非法情况,考虑到一个数的倍数个数的平方种情况里可能会出现 \(\gcd\) 不为当前数的问题,所以想到莫比乌斯反演,运用莫比乌斯反演准确求出 \(\gcd\) 为每个数的情况个数,不过这里也有猜的成分,还是看看正解,我的比较蒙的。
正解:
定义 \(A_d\) 为 \(\gcd = d\) 的倍数的方案数,\(B_d\) 为 \(\gcd = d\) 恰好的方案数,然后得到式子:
\[A_d = (m/d)^n
\]
\[B_d = A_d - \sum_{i = 2}^{m/d}B_{i\times d}
\]
其实跟莫比乌斯的大致方向是一样的,只不过这个更好理解与实现。
记得从小到大。
这里给的代码是莫比乌斯:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
const int MOD = 1e9+7;
const int N = 1e6+100;
ll cnt[N], prime[N], tot, minu[N], moi[N];
bool check[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;
}
void xxs () {
check[0] = check[1] = true;
for (int i = 0;i <= N;i++) moi[i] = 1;
for (int i = 2;i <= N;i++) {
if (!check[i]) prime[++tot] = i, moi[i] = -1;
for (int j = 1;j <= tot && i * prime[j] <= N;j++) {
check[i * prime[j]] = true;
if (!(i % prime[j])) { moi[i * prime[j]] = 0; break; }
moi[i * prime[j]] = - moi[i];
}
}
}
void solve () {
ll n, m, l, r; cin >> n >> m >> l >> r;
xxs();
ll ans = 0;
for (ll i = l;i <= r;i++) {
ll len = (m/i) % MOD;
ll tmp = 0;
for (ll k = 1;k <= len;k++) {
ll now = (ll)(m / (i*k)) % MOD;
tmp = (ll)(tmp + (ll)moi[k] * qpow(now, n) % MOD) % MOD;
}
ans = (ll)(ans + tmp) % MOD;
}
cout << (ans+MOD)%MOD << "\n";
}
int main () {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int _ = 1;
while (_--) solve();
return 0;
}
B
严重怀疑出题人脑子进水了,数据那么小,直接暴力出奇迹。
C
呃呃,其实吧,在写题解的时候,我忘记自己怎么写的了,哈哈哈哈。
其实不难发现,根据贪心我们可以想到求出 \(a_i \to b_i\) 得最小操作步数先,定义 \(c_i = (b_i - a_i + 4) \mod 4\)。
然后根据山峰图可以想到答案就是:
\[\sum_{i = 1} ^ {n-1} max(c_i - c_{i+1}, 0)
\]
发现答案就是这玩意的前缀和。
同时发现这个 \(c_i\) 不过是个摆设,真正的操作步数应该是 \(k_i = c_i \mod 4\)。(至于为什么,我想这就是数学吧)
于是考虑对 \(c_i\) 进行操作,发现可以通过修改一段区间内的 \(c_i\) 来达到减小答案步数的目的,于是手推出这三种情况:
- \(d_l = 2, d_r = -3 \to ans - 1\)
- \(d_l = 3, d_r = -2 \to ans - 1\)
- \(d_l = 3, d_r = -3 \to ans - 2\)
这里 \(d_i = c_i - c_{i+1}\),不难发现就是差分。
考虑从大到小处理,开始贪心即可。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
const int N = 1e5+100;
const int INF = 1e9+100;
ll n, a[N], b[N], minu[N], c[N];
ll res;
ll sum[N], dif[N];
ll now[N];
void solve (){
cin >> n;
for (int i = 0;i < n;i++) cin >> a[i];
for (int i = 0;i < n;i++) cin >> b[i];
int ret = 0;
for (int i = 0;i < n;i++) {
c[i] = (4 + b[i] - a[i]) % 4;
ll d = c[i];
if (i > 0) {
d += 4 - c[i-1];
d = d %4;
}
dif[i] = d, res += d, sum[i] = res;
}
for (int j = 3;j >= 0;j--) {
for (int i = n-1;i >= 0;i--) {
now[i] = sum[i];
if (i + 1 < n)
now[i] = min(now[i], now[i+1]);
}
ll minn = 0;
for (int i = 0;i < n;i++) {
sum[i] -= minn;
if (dif[i] == j && now[i] >= minn + 4)
sum[i] -= 4, res -= j, minn += 4;
}
}
cout << res << "\n";
}
int main () {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int _ = 1;
while (_--) solve();
return 0;
}
浙公网安备 33010602011771号