A – 楼房搭建
首先这题的 \(\Theta(n^3)\) 是很好写的,如果要写到 \(\Theta(n^2)\) 的分,我们可以观察到 DP 的过程其实是一个做后缀 min 的过程,所以优化完毕(当然也可以线性规划,但是很难写)。
正解比较神仙。考虑做到第 \(i\) 个时,考虑 \((2, 1)\) 的操作做满。显然这是局部最优解而不是全局最优解,然而我们考虑去反悔:考虑把 \((2, 1)\) 换成 \((1, 2)\),在用额外的一个时间去做一个 \((1, 2)\),那么我们可以在 \(i – 1\) 不动的情况下让 \(i\) 加上三个单位。其他的反悔方式类似。
大概就是这样的思路,我们可以记录上一次的次数然后贪心的换即可。
const int MAX_N = 1e6 + 200;
int n, hi[MAX_N], ai[MAX_N];
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
x = (x << 3) + (x << 1) + ch - '0', ch = nc();
freopen("building.in", "r", stdin);
freopen("building.out", "w", stdout);
for (int i = 1; i <= n; i++)
for (int i = 1; i <= n; i++)
int regret3 = min(hi[i] / 3, ai[i]);
int regret2 = hi[i] >> 1;
hi[i] = 0, ans += regret1 + regret2 + regret3;
ai[i + 1] += regret3 * 2 + regret2;
hi[i + 1] -= regret2 + regret1 * 2;
// building.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e6 + 200;
int n, hi[MAX_N], ai[MAX_N];
inline char nc()
{
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
int read()
{
int x = 0, f = 1;
char ch = nc();
while (!isdigit(ch))
{
if (ch == '-')
f = -1;
ch = nc();
}
while (isdigit(ch))
x = (x << 3) + (x << 1) + ch - '0', ch = nc();
return x * f;
}
void fileIO()
{
freopen("building.in", "r", stdin);
freopen("building.out", "w", stdout);
}
int main()
{
// fileIO();
n = read();
for (int i = 1; i <= n; i++)
hi[i] = read();
long long ans = 0;
for (int i = 1; i <= n; i++)
{
hi[i] = max(hi[i], 0);
int regret3 = min(hi[i] / 3, ai[i]);
hi[i] -= regret3 * 3;
int regret2 = hi[i] >> 1;
hi[i] -= regret2 * 2;
int regret1 = hi[i];
hi[i] = 0, ans += regret1 + regret2 + regret3;
ai[i + 1] += regret3 * 2 + regret2;
hi[i + 1] -= regret2 + regret1 * 2;
}
printf("%lld\n", ans);
return 0;
}
// building.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e6 + 200;
int n, hi[MAX_N], ai[MAX_N];
inline char nc()
{
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
int read()
{
int x = 0, f = 1;
char ch = nc();
while (!isdigit(ch))
{
if (ch == '-')
f = -1;
ch = nc();
}
while (isdigit(ch))
x = (x << 3) + (x << 1) + ch - '0', ch = nc();
return x * f;
}
void fileIO()
{
freopen("building.in", "r", stdin);
freopen("building.out", "w", stdout);
}
int main()
{
// fileIO();
n = read();
for (int i = 1; i <= n; i++)
hi[i] = read();
long long ans = 0;
for (int i = 1; i <= n; i++)
{
hi[i] = max(hi[i], 0);
int regret3 = min(hi[i] / 3, ai[i]);
hi[i] -= regret3 * 3;
int regret2 = hi[i] >> 1;
hi[i] -= regret2 * 2;
int regret1 = hi[i];
hi[i] = 0, ans += regret1 + regret2 + regret3;
ai[i + 1] += regret3 * 2 + regret2;
hi[i + 1] -= regret2 + regret1 * 2;
}
printf("%lld\n", ans);
return 0;
}
B – 手链强化
终于碰到了 Burnside 和 Polya 的题了。
首先这里的置换操作只有一个旋转,所以循环节是 \(\gcd\),所以我们只需要来算 \(\gcd\) 个等价类时的方案数。
其实等价类方案数也很好求,设 \(f[i][0], f[i][1]\) 为考虑过 \(i\) 个等价类、位置上有没有染色的方案数,直接 \(f[i][0] = f[i – 1][1] + f[i – 1][0], f[i][1] = k f[i – 1][0]\),并且发现这个矩阵快速幂也很好做。
还要注意一点,就是开头的等价类和末尾的等价类不能相邻,所以分类考虑出方案数为 \(f[t – 1][0] + f[t – 1][1] + f[t – 2][0]\)。
最后答案就是:
\[ \frac{1}{n} \sum_{d|n} (f[d – 1][0] + f[d – 1][1] + f[d – 2][0]) \varphi(\frac{n}{d}) \]
int n, kind, dp[1010][2][2];
freopen("bracelet.in", "r", stdin);
freopen("bracelet.out", "w", stdout);
int *operator[](const int &idx) { return mat[idx]; }
void clear() { memset(mat, 0, sizeof(mat)); }
matrix operator*(const matrix &rhs)
for (int i = 0; i < 2; i++)
for (int k = 0; k < 2; k++)
for (int j = 0; j < 2; j++)
ret[i][j] = (0LL + ret[i][j] + 1LL * mat[i][k] * rhs.mat[k][j] % mod) % mod;
matrix operator^(const int &idx)
ret.clear(), ret[0][0] = ret[1][1] = 1;
matrix getFn(int x) { return init * (trans ^ x); }
for (int i = 2; 1LL * i * i <= x; i++)
int fpow(int bas, int tim)
ret = 1LL * ret * bas % mod;
bas = 1LL * bas * bas % mod;
const int inv2 = fpow(2, mod - 2);
int pans = 1LL * kind * c[0][0] % mod;
pans = (0LL + pans + c[0][0] + c[0][1]) % mod;
pans = 1LL * pans * phi(n / x) % mod;
scanf("%d%d", &n, &kind), init[0][0] = 1, trans[0][0] = trans[1][0] = 1, trans[0][1] = kind;
for (int i = 1; 1LL * i * i <= n; i++)
ans = (0LL + ans + solve(i) + ((1LL * i * i == n) ? 0 : solve(n / i))) % mod;
printf("%lld\n", 1LL * ans * fpow(n, mod - 2) % mod);
@@ -0,0 +1,103 @@
// bracelet.cpp
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
int n, kind, dp[1010][2][2];
void fileIO()
{
freopen("bracelet.in", "r", stdin);
freopen("bracelet.out", "w", stdout);
}
struct matrix
{
int mat[2][2];
int *operator[](const int &idx) { return mat[idx]; }
void clear() { memset(mat, 0, sizeof(mat)); }
matrix operator*(const matrix &rhs)
{
matrix ret;
ret.clear();
for (int i = 0; i < 2; i++)
for (int k = 0; k < 2; k++)
if (mat[i][k])
for (int j = 0; j < 2; j++)
if (rhs.mat[k][j])
ret[i][j] = (0LL + ret[i][j] + 1LL * mat[i][k] * rhs.mat[k][j] % mod) % mod;
return ret;
}
matrix operator^(const int &idx)
{
int tim = idx;
matrix ret, bas = *this;
ret.clear(), ret[0][0] = ret[1][1] = 1;
while (tim)
{
if (tim & 1)
ret = ret * bas;
bas = bas * bas;
tim >>= 1;
}
return ret;
}
} trans, init;
matrix getFn(int x) { return init * (trans ^ x); }
int phi(int x)
{
int ret = x;
for (int i = 2; 1LL * i * i <= x; i++)
if (x % i == 0)
{
ret -= ret / i;
while (x % i == 0)
x /= i;
}
if (x != 1)
ret -= ret / x;
return ret % mod;
}
int fpow(int bas, int tim)
{
int ret = 1;
while (tim)
{
if (tim & 1)
ret = 1LL * ret * bas % mod;
bas = 1LL * bas * bas % mod;
tim >>= 1;
}
return ret;
}
const int inv2 = fpow(2, mod - 2);
int solve(int x)
{
if (x == 1)
return phi(n / x);
matrix c = getFn(x - 2);
int pans = 1LL * kind * c[0][0] % mod;
c = c * trans;
pans = (0LL + pans + c[0][0] + c[0][1]) % mod;
pans = 1LL * pans * phi(n / x) % mod;
return pans;
}
int main()
{
// fileIO();
scanf("%d%d", &n, &kind), init[0][0] = 1, trans[0][0] = trans[1][0] = 1, trans[0][1] = kind;
int ans = 0;
for (int i = 1; 1LL * i * i <= n; i++)
if (n % i == 0)
ans = (0LL + ans + solve(i) + ((1LL * i * i == n) ? 0 : solve(n / i))) % mod;
printf("%lld\n", 1LL * ans * fpow(n, mod - 2) % mod);
return 0;
}
@@ -0,0 +1,103 @@
// bracelet.cpp
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
int n, kind, dp[1010][2][2];
void fileIO()
{
freopen("bracelet.in", "r", stdin);
freopen("bracelet.out", "w", stdout);
}
struct matrix
{
int mat[2][2];
int *operator[](const int &idx) { return mat[idx]; }
void clear() { memset(mat, 0, sizeof(mat)); }
matrix operator*(const matrix &rhs)
{
matrix ret;
ret.clear();
for (int i = 0; i < 2; i++)
for (int k = 0; k < 2; k++)
if (mat[i][k])
for (int j = 0; j < 2; j++)
if (rhs.mat[k][j])
ret[i][j] = (0LL + ret[i][j] + 1LL * mat[i][k] * rhs.mat[k][j] % mod) % mod;
return ret;
}
matrix operator^(const int &idx)
{
int tim = idx;
matrix ret, bas = *this;
ret.clear(), ret[0][0] = ret[1][1] = 1;
while (tim)
{
if (tim & 1)
ret = ret * bas;
bas = bas * bas;
tim >>= 1;
}
return ret;
}
} trans, init;
matrix getFn(int x) { return init * (trans ^ x); }
int phi(int x)
{
int ret = x;
for (int i = 2; 1LL * i * i <= x; i++)
if (x % i == 0)
{
ret -= ret / i;
while (x % i == 0)
x /= i;
}
if (x != 1)
ret -= ret / x;
return ret % mod;
}
int fpow(int bas, int tim)
{
int ret = 1;
while (tim)
{
if (tim & 1)
ret = 1LL * ret * bas % mod;
bas = 1LL * bas * bas % mod;
tim >>= 1;
}
return ret;
}
const int inv2 = fpow(2, mod - 2);
int solve(int x)
{
if (x == 1)
return phi(n / x);
matrix c = getFn(x - 2);
int pans = 1LL * kind * c[0][0] % mod;
c = c * trans;
pans = (0LL + pans + c[0][0] + c[0][1]) % mod;
pans = 1LL * pans * phi(n / x) % mod;
return pans;
}
int main()
{
// fileIO();
scanf("%d%d", &n, &kind), init[0][0] = 1, trans[0][0] = trans[1][0] = 1, trans[0][1] = kind;
int ans = 0;
for (int i = 1; 1LL * i * i <= n; i++)
if (n % i == 0)
ans = (0LL + ans + solve(i) + ((1LL * i * i == n) ? 0 : solve(n / i))) % mod;
printf("%lld\n", 1LL * ans * fpow(n, mod - 2) % mod);
return 0;
}
C – 数字收藏
不难,发现贡献是莫比乌斯函数乘上已有倍数个数,所以写完了。
const int MAX_N = 1e5 + 200;
int n, d, mu[MAX_N], primes[MAX_N], tot, psiz[MAX_N];
freopen("number.in", "r", stdin);
freopen("number.out", "w", stdout);
static char buf[1000000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++;
x = (x << 3) + (x << 1) + ch - '0', ch = nc();
for (int i = 2; i < MAX_N; i++)
primes[++tot] = i, mu[i] = -1;
for (int j = 1; j <= tot && 1LL * i * primes[j] < MAX_N; j++)
vis[i * primes[j]] = true, mu[i * primes[j]] = -mu[i];
// printf("%.6lf\n", 1.0 * clock() / CLOCKS_PER_SEC);
int opt = read(), x = read();
for (int i = 1; 1LL * i * i <= x; i++)
ans += mu[i] * psiz[i], psiz[i]++;
ans += mu[x / i] * psiz[x / i], psiz[x / i]++;
if (pos.find(x) == pos.end())
for (int i = 1; 1LL * i * i <= x; i++)
psiz[i]--, ans -= mu[i] * psiz[i];
psiz[x / i]--, ans -= mu[x / i] * psiz[x / i];
// printf("%.6lf\n", 1.0 * clock() / CLOCKS_PER_SEC);
@@ -0,0 +1,104 @@
// number.cpp
#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e5 + 200;
typedef long long ll;
int n, d, mu[MAX_N], primes[MAX_N], tot, psiz[MAX_N];
bool vis[MAX_N];
multiset<int> pos;
ll ans;
void fileIO()
{
freopen("number.in", "r", stdin);
freopen("number.out", "w", stdout);
}
inline char nc()
{
static char buf[1000000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++;
}
int read()
{
int x = 0, f = 1;
char ch = nc();
while (!isdigit(ch))
{
if (ch == '-')
f = -1;
ch = nc();
}
while (isdigit(ch))
x = (x << 3) + (x << 1) + ch - '0', ch = nc();
return x * f;
}
int main()
{
// fileIO();
n = read(), d = read();
mu[1] = 1;
for (int i = 2; i < MAX_N; i++)
{
if (!vis[i])
primes[++tot] = i, mu[i] = -1;
for (int j = 1; j <= tot && 1LL * i * primes[j] < MAX_N; j++)
{
vis[i * primes[j]] = true, mu[i * primes[j]] = -mu[i];
if (i % primes[j] == 0)
{
mu[i * primes[j]] = 0;
break;
}
}
}
// printf("%.6lf\n", 1.0 * clock() / CLOCKS_PER_SEC);
// answer the queries;
while (n--)
{
int opt = read(), x = read();
if (x % d != 0)
{
printf("%lld\n", ans);
continue;
}
x /= d;
if (opt == 1)
{
pos.insert(x);
for (int i = 1; 1LL * i * i <= x; i++)
if (x % i == 0)
{
ans += mu[i] * psiz[i], psiz[i]++;
if (x / i != i)
ans += mu[x / i] * psiz[x / i], psiz[x / i]++;
}
}
else
{
if (pos.find(x) == pos.end())
{
printf("%lld\n", ans);
continue;
}
pos.erase(pos.find(x));
for (int i = 1; 1LL * i * i <= x; i++)
if (x % i == 0)
{
psiz[i]--, ans -= mu[i] * psiz[i];
if (x / i != i)
psiz[x / i]--, ans -= mu[x / i] * psiz[x / i];
}
}
printf("%lld\n", ans);
}
// printf("%.6lf\n", 1.0 * clock() / CLOCKS_PER_SEC);
return 0;
}
@@ -0,0 +1,104 @@
// number.cpp
#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e5 + 200;
typedef long long ll;
int n, d, mu[MAX_N], primes[MAX_N], tot, psiz[MAX_N];
bool vis[MAX_N];
multiset<int> pos;
ll ans;
void fileIO()
{
freopen("number.in", "r", stdin);
freopen("number.out", "w", stdout);
}
inline char nc()
{
static char buf[1000000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++;
}
int read()
{
int x = 0, f = 1;
char ch = nc();
while (!isdigit(ch))
{
if (ch == '-')
f = -1;
ch = nc();
}
while (isdigit(ch))
x = (x << 3) + (x << 1) + ch - '0', ch = nc();
return x * f;
}
int main()
{
// fileIO();
n = read(), d = read();
mu[1] = 1;
for (int i = 2; i < MAX_N; i++)
{
if (!vis[i])
primes[++tot] = i, mu[i] = -1;
for (int j = 1; j <= tot && 1LL * i * primes[j] < MAX_N; j++)
{
vis[i * primes[j]] = true, mu[i * primes[j]] = -mu[i];
if (i % primes[j] == 0)
{
mu[i * primes[j]] = 0;
break;
}
}
}
// printf("%.6lf\n", 1.0 * clock() / CLOCKS_PER_SEC);
// answer the queries;
while (n--)
{
int opt = read(), x = read();
if (x % d != 0)
{
printf("%lld\n", ans);
continue;
}
x /= d;
if (opt == 1)
{
pos.insert(x);
for (int i = 1; 1LL * i * i <= x; i++)
if (x % i == 0)
{
ans += mu[i] * psiz[i], psiz[i]++;
if (x / i != i)
ans += mu[x / i] * psiz[x / i], psiz[x / i]++;
}
}
else
{
if (pos.find(x) == pos.end())
{
printf("%lld\n", ans);
continue;
}
pos.erase(pos.find(x));
for (int i = 1; 1LL * i * i <= x; i++)
if (x % i == 0)
{
psiz[i]--, ans -= mu[i] * psiz[i];
if (x / i != i)
psiz[x / i]--, ans -= mu[x / i] * psiz[x / i];
}
}
printf("%lld\n", ans);
}
// printf("%.6lf\n", 1.0 * clock() / CLOCKS_PER_SEC);
return 0;
}