[题解]不会真有人要打树套树吧
作者:互联网
\(\mathcal{Back\;To\;The\;Menu}\).
2022-03-19 不会真有人要打树套树吧
T2 花的时间太多了,还是不大行。
太阳照常升起 / Lost
注意到 \(\tau(n)\) 是个完全积性函数,而 \(\xi=\tau*1\),那 \(\xi(n)\) 也就是积性函数。由于 \(\xi(p)(p\in \Bbb P)\),因此,你会发现 \(\xi(n)\) 有值当且仅当 \(n\) 为完全平方数,且此时 \(\xi(n)=1\).
因此现在的问题就变成了求可重集 \(\set{ij|1\le i\le n,1\le j\le m}\) 中有多少是完全平方数,由经典结论:若 \(ab\) 为完全平方数,那么存在 \(m,s,t\) 使得 \(ms^2=a,mt^b=b\) 且 \(\mu(m)\neq 0\)(即 \(m\) 中不含平方因子),因此,我们可以考虑枚举这个 \(m\):
\[\sum_{i=1}^n\floor{\sqrt{\ddiv{n}{i}}}\floor{\sqrt{\ddiv{m}{i}}}\mu^2(i) \]其中含有 \(\mu^2(i)\) 是指我们只统计 \(\mu(i)\neq 0\) 的 \(i\). 走到这一步之后,你可以使用 \(\mathcal O(\sqrt n)\) 的复杂度来解决这个问题,只是你需要求得 \(\sum \mu^2(i)\),这个东西挺困难,因此我们需要将其再一步变形,,考虑使用一个替换:\(\displaystyle \mu^2(i)=\sum_{d^2\mid i}\mu(d)\),其证明可以使用贝尔级数:
不难知道 \(\mu^2_p(z)=1+z,\mu_p(z)=1-z,1_p(z)=\frac{1}{1-z}\),因此 \(\mu^2_p(z)=\mu_p(z^2)\times 1_p(z)\),其中 \(\mu_p(z^2)\) 即要求 \(d^2\mid i\),然后就是 \(\mu\) 卷上 \(1\).
然后继续推式子:
\[(*)=\sum_{i=1}^n\floor{\sqrt{\ddiv{n}{i}}}\floor{\sqrt{\ddiv{m}{i}}}\sum_{d^2\mid i}\mu(d)=\sum_{d=1}^{\sqrt n}\mu(d)\sum_{i=1}^n\floor{\sqrt{\ddiv{n}{id^2}}}\floor{\sqrt{\ddiv{m}{id^2}}} \] 注意后面的根号部分可以数论分块,此时总复杂度就是 \(\mathcal O(\sqrt n\ln n)\). 但是宋队积出来发现时间复杂度只是 \(\mathcal \require{enclose}\enclose{horizontalstrike}{O(\sqrt n)}\) 的,并不明白对数是哪里来的。
/** @author __Elaina__ */
// #pragma GCC optimize("O2")
#include <bits/stdc++.h>
using namespace std;
#define USING_FREAD
// #define NDEBUG
#include <cassert>
namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */
#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define repf(i, l, r) for (int i = (l), i##_end_ = (r); i < i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER
#define masdf(...) fprintf(stderr, __VA_ARGS__)
typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;
typedef vector<int> vset;
template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void chkmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void chkmax(T& x, const T rhs) { x = std::max(x, rhs); }
#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI ((char)getchar())
#endif
template<class T> inline T readret(T x) {
x = 0; int f = 0; char c;
while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
return f ? -x : x;
}
template<class T> inline void readin(T& x) {
x = 0; int f = 0; char c;
while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
if (x < 0) putchar('-'), x = -x;
static int __stk[55], __bit = 0;
do __stk[++__bit] = x % 10, x /= 10; while (x);
while (__bit) putchar(__stk[__bit--] ^ 48);
putchar(c);
}
template<class T> inline T listMax(const T& x) { return x; }
template<class T, class... Args> inline T listMax(const T& x, const Args&... args) {
return max(x, listMax(args...));
}
template<class T> inline T listMin(const T& x) { return x; }
template<class T, class... Args> inline T listMin(const T& x, const Args&... args) {
return min(x, listMin(args...));
}
} // namespace Elaina
using namespace Elaina;
// int tau[Maxn + 5], prime[Maxn + 5];
// bool vis[Maxn + 5];
// int xi[Maxn + 5];
// inline void prelude() {
// vis[1] = true, tau[1] = 1;
// rep (i, 2, Maxn) {
// if (!vis[i]) prime[++*prime] = i, tau[i] = -1;
// for (int j = 1; j <= *prime && i * prime[j] <= Maxn; ++j) {
// vis[i * prime[j]] = true;
// tau[i * prime[j]] = -tau[i];
// if (i % prime[j] == 0) break;
// }
// }
// // rep (i, 1, Maxn) masdf("tau[%d] == %d\n", i, tau[i]);
// rep (i, 1, Maxn) {
// for (int d = 1; d * d <= i; ++d) if (i % d == 0) {
// xi[i] += tau[d];
// if (i != d * d) xi[i] += tau[i / d];
// }
// if (xi[i] != 0) printf("xi[%d] == %d\n", i, xi[i]);
// }
// }
const int Maxn = 1e6;
bool vis[Maxn + 5];
int prime[Maxn + 5], mu[Maxn + 5];
inline void prelude() {
vis[1] = true, mu[1] = 1;
rep (i, 2, Maxn) {
if (!vis[i]) prime[++*prime] = i, mu[i] = -1;
for (int j = 1; j <= *prime && i * prime[j] <= Maxn; ++j) {
vis[i * prime[j]] = true, mu[i * prime[j]] = -mu[i];
if (i % prime[j] == 0) { mu[i * prime[j]] = 0; break; }
}
}
}
ll n, m;
inline ll work(ll n, ll m) {
ll ret = 0;
for (ll l = 1, r; l <= n; l = r + 1) {
r = min(n / (n / l), m / (m / l));
ret += (ll)sqrt(n / l) * (ll)sqrt(m / l) * (r - l + 1);
}
return ret;
}
signed main() {
freopen("lost.in", "r", stdin);
freopen("lost.out", "w", stdout);
prelude();
readin(n, m);
if (n > m) swap(n, m);
ll ans = 0;
for (ll i = 1; i * i <= n; ++i) if (mu[i])
ans += mu[i] * work(n / (i * i), m / (i * i));
writln(ans);
return 0;
}
丧钟为谁而鸣 / Harmony
注意到 \(p\ge 20\),因此,若我们随机一次,某个答案没有被随机到的概率为 \(80\%\),如果多来几次,比如来 \(60\) 次,这个概率将会变成 \(p=(0.8)^{60}\approx 1.53249554\times 10^{-6}\). 因此,我们可以随机取一个区间中的数,然后数这个数在该区间中的出现次数。
对于数字的统计考虑使用分块,注意在处理散块的时候要顺便将该散块的桶同时清空,总复杂度就是 \(\mathcal O(m\sqrt n\times 60)\).
/** @author __Elaina__ */
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
#define USING_FREAD
// #define NDEBUG
#include <cassert>
namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */
#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define repf(i, l, r) for (int i = (l), i##_end_ = (r); i < i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER
#define masdf(...) fprintf(stderr, __VA_ARGS__)
typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;
typedef vector<int> vset;
template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void chkmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void chkmax(T& x, const T rhs) { x = std::max(x, rhs); }
#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI ((char)getchar())
#endif
template<class T> inline T readret(T x) {
x = 0; int f = 0; char c;
while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
return f ? -x : x;
}
template<class T> inline void readin(T& x) {
x = 0; int f = 0; char c;
while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
if (x < 0) putchar('-'), x = -x;
static int __stk[55], __bit = 0;
do __stk[++__bit] = x % 10, x /= 10; while (x);
while (__bit) putchar(__stk[__bit--] ^ 48);
putchar(c);
}
template<class T> inline T listMax(const T& x) { return x; }
template<class T, class... Args> inline T listMax(const T& x, const Args&... args) {
return max(x, listMax(args...));
}
template<class T> inline T listMin(const T& x) { return x; }
template<class T, class... Args> inline T listMin(const T& x, const Args&... args) {
return min(x, listMin(args...));
}
} // namespace Elaina
using namespace Elaina;
const int Maxm = 3e4;
const int Maxn = 1e5 + 3e4 + 5;
const int Blo = 320;
// const int Maxm = 100;
// const int Maxn = 100;
// const int Blo = 1;
int a[Maxn + 5], n, m, perc;
int blef[Maxn / Blo + 5], brig[Maxn / Blo + 5], bel[Maxn + 5], bcnt;
int tag[Maxn / Blo + 5]; // the number which cover the block
int op[Maxn + 5], ql[Maxn + 5], qr[Maxn + 5], qt[Maxn + 5];
int arr[Maxn + 5], siz;
int buc[Maxn / Blo + 5][Maxn + 5];
inline void prelude() {
sort(arr + 1, arr + siz + 1);
siz = unique(arr + 1, arr + siz + 1) - arr - 1;
memset(tag, 0xff, sizeof tag);
rep (i, 1, n) a[i] = lower_bound(arr + 1, arr + siz + 1, a[i]) - arr;
rep (i, 1, m) if (op[i] == 1) qt[i] = lower_bound(arr + 1, arr + siz + 1, qt[i]) - arr;
for (int i = 1; (i - 1) * Blo + 1 <= n; ++i) {
bcnt = i;
blef[i] = (i - 1) * Blo + 1, brig[i] = min(i * Blo, n);
rep (j, blef[i], brig[i]) bel[j] = i, ++buc[i][a[j]];
}
}
inline void filbuc(int id, int x) {
rep (i, blef[id], brig[id]) buc[id][a[i]] += x;
}
inline void pushdown(int id) {
if (!~tag[id]) return ;
rep (j, blef[id], brig[id]) {
--buc[id][a[j]];
++buc[id][a[j] = tag[id]];
}
tag[id] = -1;
}
inline void update(int ql, int qr, int x) {
if (bel[ql] == bel[qr]) {
pushdown(bel[ql]);
rep (i, ql, qr) {
--buc[bel[ql]][a[i]];
++buc[bel[ql]][a[i] = x];
}
return ;
}
pushdown(bel[ql]), pushdown(bel[qr]);
rep (i, ql, brig[bel[ql]]) {
--buc[bel[ql]][a[i]];
++buc[bel[ql]][a[i] = x];
}
rep (i, bel[ql] + 1, bel[qr] - 1) tag[i] = x;
rep (i, blef[bel[qr]], qr) {
--buc[bel[qr]][a[i]];
++buc[bel[qr]][a[i] = x];
}
return ;
}
inline int query(int ql, int qr, int x) {
int ret = 0;
if (bel[ql] == bel[qr]) {
pushdown(bel[ql]);
rep (i, ql, qr) ret += (a[i] == x);
return ret;
}
pushdown(bel[ql]), pushdown(bel[qr]);
rep (i, ql, brig[bel[ql]]) ret += (a[i] == x);
rep (i, bel[ql] + 1, bel[qr] - 1) {
if (tag[i] == -1) ret += buc[i][x];
else ret += (tag[i] == x) * (brig[i] - blef[i] + 1);
}
rep (i, blef[bel[qr]], qr) ret += (a[i] == x);
return ret;
}
mt19937 rnd(0xcbdd1);
// inline ull regen() {
// return ((rnd() ^ rnd() | rnd() & rnd()) & 0x7fff) << 15 | ((rnd() ^ rnd() | rnd() & rnd()) & 0x7fff);
// }
inline int gen(int l, int r) {
return rnd() % (r - l + 1) + l;
}
unordered_map<int, bool> used;
int ans[Maxn + 5], ans_siz;
inline void solve(int ql, int qr) {
int mxx = 0, len = qr - ql + 1;
used.clear(), ans_siz = 0;
rep (_, 1, 100) {
int p = gen(ql, qr);
if (used.count(p)) continue;
used[p] = true;
p = (tag[bel[p]] == -1? a[p]: tag[bel[p]]);
int cnt = query(ql, qr, p);
if (cnt * 100 < len * perc) continue;
if (cnt > mxx) ans[ans_siz = 1] = p, mxx = cnt;
else if (cnt == mxx) ans[++ans_siz] = p;
// if (ans_siz == 100 / perc) break;
if ((int)used.size() >= 60) break;
}
sort(ans + 1, ans + ans_siz + 1);
ans_siz = unique(ans + 1, ans + ans_siz + 1) - ans - 1;
writln(ans_siz, ' ');
rep (i, 1, ans_siz) writln(arr[ans[i]], ' ');
Endl;
}
inline void work() {
rep (i, 1, m) {
if (op[i] == 1) update(ql[i], qr[i], qt[i]);
else solve(ql[i], qr[i]);
}
}
signed main() {
freopen("harmony.in", "r", stdin);
freopen("harmony.out", "w", stdout);
readin(n, m, perc);
rep (i, 1, n) readin(a[i]), arr[++siz] = a[i];
rep (i, 1, m) {
readin(op[i], ql[i], qr[i]);
if (op[i] == 1) readin(qt[i]), arr[++siz] = qt[i];
}
prelude();
work();
return 0;
}
老人与海 / Dignity
注意每种武器的 OGF 为 \(\displaystyle \frac{1}{1-x^{a_i}}\),因此
\[f(T)=[x^T]\prod_{i=1}^n \frac{1}{1-x^{a_i}} \]但是他们全是分式,不是特别好处理,令 \(W=\lcm(a_i)\),那么,我们可以将原式写成:
\[f(T)=[x^T]\frac{1}{(1-x^W)^n}\prod_{i=1}^n\frac{1-x^W}{1-x^{a_i}} \\ =[x^T]\brak{\sum_{i=0}^{+\infty}x^{iW}}^n\prod_{i=1}^n\brak{\sum_{j=0}^{(W/a_i)-1}x^{j\times a_i}} \]这个多项式考虑分成两个部分:\(\displaystyle \brak{\sum_{i=0}^{+\infty}x^{iW}}^n\) 和 \(\displaystyle \prod_{i=1}^n\brak{\sum_{j=0}^{(W/a_i)-1}x^{j\times a_i}}\),前半部分只有 \(x^{iW}\) 项,并且其系数为 \(\displaystyle {n+i-1\choose i-1}\),后半部分是一个次数很低的多项式,可以直接做多项式乘法得到,记前者为多项式 \(Q\),后者为多项式 \(P\).
于是,可以将 \(T=kW+r\),记 \(f(T)=G(k,r)\),并且对于 \(G(k,r)\),我们有
\[G(k,r)=\sum_{i=0}^{k}q((k-i)W)+p(iW+r)=\sum_{i=0}^k{n+k-i-1\choose n-1}p(iW+r) \]在原问题中,我们要找到最小的 \(T\) 使得 \(f(T)\ge h_i\),只需要对每个 \(\bmod W\) 的余数都做一次二分即可,因为显然当 \(r\) 固定时,\(G(k,r)\) 随 \(k\) 单增。
/** @author __Elaina__ */
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
#define USING_FREAD
// #define NDEBUG
#include <cassert>
namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */
#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define repf(i, l, r) for (int i = (l), i##_end_ = (r); i < i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER
#define masdf(...) fprintf(stderr, __VA_ARGS__)
typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;
typedef vector<int> vset;
template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void chkmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void chkmax(T& x, const T rhs) { x = std::max(x, rhs); }
#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI ((char)getchar())
#endif
template<class T> inline T readret(T x) {
x = 0; int f = 0; char c;
while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
return f ? -x : x;
}
template<class T> inline void readin(T& x) {
x = 0; int f = 0; char c;
while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
if (x < 0) putchar('-'), x = -x;
static int __stk[55], __bit = 0;
do __stk[++__bit] = x % 10, x /= 10; while (x);
while (__bit) putchar(__stk[__bit--] ^ 48);
putchar(c);
}
template<class T> inline T listMax(const T& x) { return x; }
template<class T, class... Args> inline T listMax(const T& x, const Args&... args) {
return max(x, listMax(args...));
}
template<class T> inline T listMin(const T& x) { return x; }
template<class T, class... Args> inline T listMin(const T& x, const Args&... args) {
return min(x, listMin(args...));
}
} // namespace Elaina
using namespace Elaina;
const int Maxn = 1e5;
const ll inf = 1ll << 60;
int a[Maxn + 5], n, W = 1, q;
int p[Maxn + 5], m;
inline void input() {
readin(n);
rep (i, 1, n) {
readin(a[i]);
int g = __gcd(a[i], W);
W = W / g * a[i];
}
// masdf("W == %d\n", W);
}
int tmp[Maxn + 5];
inline void solveP() {
p[0] = 1, m = 1;
rep (i, 1, n) {
int mxp = 0;
repf (j, 0, m) if (p[j])
repf (t, 0, W / a[i])
tmp[j + t * a[i]] += p[j], chkmax(mxp, j + t * a[i]);
chkmax(m, mxp + 1);
memcpy(p, tmp, m << 2);
memset(tmp, 0, m << 2);
}
// repf (i, 0, m) masdf("%d ", p[i]); Endl;
}
inline ll C(ll n, ll m) {
ll ret = 1;
for (int i = 1; i <= m; ++i, --n)
ret *= n;
rep (i, 1, m) ret /= i;
return ret;
}
inline ll check(ll k, int r, const ll& tar) {
ll fun_val = 0;
for (int i = 0; ; ++i) {
int now = i * W + r;
if (now >= m) break;
if (!p[now]) continue; // useless
// to avoid ll leak
ll res = tar - fun_val;
repf (t, 1, n) res *= t;
res /= p[now];
repf (t, 1, n) {
if (n + k - i - t == 0) { res = inf; break; }
res /= (n + k - i - t);
}
if (res <= 0) return true;
fun_val += C(n + k - i - 1, n - 1) * p[now];
}
return fun_val >= tar;
}
signed main() {
freopen("dignity.in", "r", stdin);
freopen("dignity.out", "w", stdout);
input();
solveP();
readin(q);
while (q--) {
ll h, ans = inf; readin(h);
repf (r, 0, W) {
ll pl = 0, pr = min((100 * h - r) / W, (ans - r) / W);
if (!check(pr, r, h)) continue;
ll resk = -1;
for (ll mid = pl + pr >> 1; pl <= pr; mid = pl + pr >> 1)
if (check(mid, r, h)) resk = mid, pr = mid - 1;
else pl = mid + 1;
if (~resk) chkmin(ans, resk * W + r);
}
if (ans == inf) puts("What a pity!");
else writln(ans);
}
return 0;
}
标签:__,有人,const,int,题解,打树套,ans,inline,define 来源: https://www.cnblogs.com/Arextre/p/16030755.html