来自学长的馈赠2 社论
T1 代码
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int N = 2e5 + 7, P = 1e9 + 7;
inline void fstmod(int& x){if (x >= P) x -= P;}
namespace NumberTheory
{
inline int qpow(int a, int n)
{
int ans = 1;
while (n)
{
if (n & 1) ans = 1ll * ans * a % P;
a = 1ll * a * a % P; n >>= 1;
} return ans;
}
inline int inv(int x){return qpow(x, P-2);}
}
vi conv(const vi& a, const vi& b)
{
assert(a.size() == b.size());
int n; vi c(n = a.size());
for (int i=0; i<n; i++)
for (int j=0; j<n; j++) fstmod(c[i*j%n] += 1ll * a[i] * b[j] % P);
return c;
}
vi qpow(vi a, int n)
{
vi ans(a.size()); ans[1] = 1;
while (n)
{
if (n & 1) ans = conv(ans, a);
a = conv(a, a); n >>= 1;
} return ans;
}
int n, m, mod;
vi a;
int main()
{
scanf("%d%d%d", &n, &m, &mod); a.resize(mod); int inv2 = NumberTheory :: inv(n);
for (int i=0, x; i<n; i++) scanf("%d", &x), ++a[x %= mod];
for (int i=0; i<mod; i++) a[i] = 1ll * a[i] * inv2 % P;
a = qpow(a, m);
int ans = 0;
for (int i=0; i<mod; i++) ans = (ans + 1ll * i * a[i] % P) % P;
printf("%d\n", ans);
return 0;
}
T2 代码
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e5 + 7;
int n, a[N], b[N];
vector<int> g[N];
inline void addedge(int u, int v){g[u].emplace_back(v);}
inline void ade(int u, int v){addedge(u, v); addedge(v, u);}
namespace encode
{
int dfn[N], idf[N], dep[N], siz[N], cc, leaf;
void dfs(int u, int fa)
{
dfn[idf[u] = ++cc] = u; siz[u] = 1; dep[u] = dep[fa] + 1;
for (int v : g[u])
{
if (v == fa) continue;
dfs(v, u); siz[u] += siz[v];
}
if (siz[u] == 1) leaf = u;
}
bool vis[N];
int dist[N], s[N];
inline int sum(int l, int r){return s[r] - s[l-1];}
inline int subtreesum(int u){return sum(idf[u], idf[u]+siz[u]-1);}
inline int bfs(int u)
{
memset(vis, false, sizeof vis);
memset(dist, 0, sizeof dist);
queue<int> q; q.push(u);
while (!q.empty())
{
int u = q.front(); q.pop();
if (vis[u]) continue;
vis[u] = true;
for (int v : g[u])
{
if (vis[v]) continue;
dist[v] = dist[u] + 1; q.push(v);
}
}
int ans = 0;
for (int i=1; i<=n; i++) ans += a[i] * dist[i];
return b[u] = ans;
}
inline void dfs2(int u, int fa)
{
for (int v : g[u])
{
if (v == fa) continue;
int add, sub;
if (dep[u] > dep[v]){add = subtreesum(u); sub = sum(1, cc) - add;}
else{sub = subtreesum(v); add = sum(1, cc) - sub;}
b[v] = b[u] + add - sub; dfs2(v, u);
}
}
inline void main()
{
memset(b, 0, sizeof b);
for (int i=1; i<=n; i++) scanf("%d", a+i);
cc = 0; dfs(1, 0);
for (int i=1; i<=n; i++) s[i] = s[i-1] + a[dfn[i]];
bfs(leaf); dfs2(leaf, 0);
for (int i=1; i<=n; i++) printf("%d ", b[i]);
puts("");
}
}
namespace decode
{
ll s[N], dif[N], sum;
inline void dfs1(int u, int fa)
{
for (int v : g[u])
{
if (v == fa) continue;
dif[v] = b[v] - b[u]; sum += dif[v];
dfs1(v, u);
}
}
inline void dfs2(int u, int fa)
{
a[u] = s[u];
for (int v : g[u])
{
if (v == fa) continue;
s[v] = (s[1] - dif[v]) / 2;
a[u] -= s[v];
dfs2(v, u);
}
}
inline void main()
{
sum = 0;
for (int i=1; i<=n; i++) scanf("%d", b+i);
dfs1(1, 0); s[1] = (sum + (b[1] << 1)) / (n-1); dfs2(1, 0);
for (int i=1; i<=n; i++) printf("%d ", a[i]);
puts("");
}
}
inline void solve()
{
scanf("%d", &n);
for (int i=1, u, v; i<n; i++) scanf("%d%d", &u, &v), ade(u, v);
int type; scanf("%d", &type);
if (type) decode :: main();
else encode :: main();
do g[n].clear(); while (n--);
}
int main()
{
int T; scanf("%d", &T);
while (T--) solve();
return 0;
}
T3 代码
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 2e5 + 7, P = 1e9 + 7;
int n, type, fac[N], ifac[N];
inline int qpow(int a, int n)
{
int ans = 1;
while (n)
{
if (n & 1) ans = 1ll * ans * a % P;
a = 1ll * a * a % P; n >>= 1;
} return ans;
}
inline int inv(int x){return qpow(x, P-2);}
inline void init()
{
fac[0] = ifac[0] = 1;
for (int i=1; i<N; i++) fac[i] = 1ll * fac[i-1] * i % P;
ifac[N-1] = inv(fac[N-1]);
for (int i=N-2; i>=1; i--) ifac[i] = 1ll * ifac[i+1] * (i+1) % P;
}
inline int binom(int n, int m){return n < m ? 0 : 1ll * fac[n] * ifac[m] % P * ifac[n-m] % P;}
inline void fstmod(int& x){if (x >= P) x -= P;}
namespace Subtask0
{
void main()
{
int ans = 0;
for (int k=0; k<=n; k+=2)
ans = (ans + 1ll * binom(k, k>>1) * binom(n-k, (n-k)>>1) % P * binom(n, k) % P) % P;
printf("%d\n", ans);
}
}
namespace Subtask1
{
int f[N];
inline void init()
{
f[0] = 1;
for (int i=1; i<N; i++) f[i] = 1ll * f[i-1] * ((i << 2) - 2) % P * inv(i+1) % P;
}
void main(){printf("%d\n", f[n >> 1]);}
}
namespace Subtask2
{
int dp[N];
void main()
{
dp[0] = 1; n >>= 1;
for (int i=1; i<=n; i++)
for (int j=0; j<i; j++)
fstmod(dp[i] += 4ll * dp[j] * Subtask1 :: f[i-j-1] % P);
printf("%d\n", dp[n]);
}
}
namespace Subtask3
{
void main()
{
int ans = 0;
for (int k=0; k<=n; k+=2)
ans = (ans + 1ll * Subtask1 :: f[k >> 1] * Subtask1 :: f[(n-k) >> 1] % P * binom(n, k) % P) % P;
printf("%d\n", ans);
}
}
int main()
{
init(); Subtask1 :: init();
scanf("%d%d", &n, &type);
if (type == 0) Subtask0 :: main();
if (type == 1) Subtask1 :: main();
if (type == 2) Subtask2 :: main();
if (type == 3) Subtask3 :: main();
return 0;
}
T4 代码
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 55, P = 998244353;
int n, lim, dp[N][N][N * N];
inline void fstmod(int& x){if (x >= P) x -= P;}
inline void chksum(int& a, const int& b){fstmod(a += b);}
int main()
{
scanf("%d%d", &n, &lim);
dp[1][0][0] = 1;
for (int i=2; i<=n; i++)
for (int j=0; j<=n-i+1; j++)
for (int k=0; k<=lim; k++)
{
if (!dp[i-1][j][k]) continue;
int _ = dp[i-1][j][k];
if (j)
{
chksum(dp[i][j-1][k+2*i], 1ll * _ * j % P); // case 1
chksum(dp[i][j][k+i], 2ll * _ * j % P); // case 2
chksum(dp[i][j+1][k], 1ll * _ * j % P); // case 3
}
chksum(dp[i][j][k+i], 2ll * _ % P); // case 4
chksum(dp[i][j+1][k], 2ll * _ % P) ; // case 5
}
int ans = 0;
for (int i=0; i<=lim; i++) chksum(ans, dp[n][0][i]);
printf("%d\n", ans);
return 0;
}
随
\(mod\) 三个字母太长了,先改成 \(P\) .
令 \(dp_{i,j}\) 为 \(i\) 次操作后 \(x=j\) 的概率,于是可以直接转移,矩阵快速幂优化即可做到 \(O(P^3\log m)\) .
但是这个看起来和题解一模一样,于是我们换一个做法 .
定义 Dirichlet 循环卷积为:
其中 \(a,b\) 是两个长度为 \(n\) 的序列 .
令 \(c_i\) 表示 \(a_i\) 中 \(i\) 出现的次数,即 \(\displaystyle c_i=\sum_{k=1}^n[a_i=k]\) .
我们维护(迫真)一个序列 \(\{P\}\) . 其中 \(P_i\) 表示操作若干次后 \(x=i\) 的概率 .
那么我们考虑把 \(\{P\}\) 往后推一次操作,根据操作的定义我们可以发现这个就是等价于把 \(\{P\}\) 卷上 \(\{c\}\)(Dirichlet 循环卷积意义下的)
显而易见 Dirichlet 循环卷积有结合律,于是直接快速幂即可 .
可以发现这个做法等价于 DP,但是时间复杂度是 \(O(P^2\log P)\) 的 .
如果可以做 Dirichlet 的 exp/ln 大概就可以优化到 \(O(P^2)\) 了罢
附:artalter 的做法我不是很懂,但是应该也是本质相同的 .
附附:标程做法大概是用原根把乘变加然后就变成普通循环卷积了吧(可以 DFT)……然而出题人自己整了个模数 \(10^9+7\) /kx .
单
\(t=0\)
这个是平凡的,首先 BFS 一下随便求出一个点的 \(b\) 值,然后考虑移动一步产生的贡献即可 .
\(t=1\)
先随便钦定一个根,方便计算 .
做一些约定:
- \(u\) 的父亲记作 \(\operatorname{father}(u)\) .
- \(u\) 的子树点权和记作 \(\displaystyle\operatorname{sum}(u)=\sum_{v\in\operatorname{subtree}(x)}a_v\) .
考虑对 \(\{b\}\) 做一次差分:
然后手解一下就好,\(O(n)\) .
注意:
- 多组数据要清空 .
- 答案不超过
int
不代表中间结果不超过int
.
题
令 \(\displaystyle C_k=\dfrac{\dbinom{2n}n}{n+1}\) 为卡特兰数第 \(k\) 项 .
\(typ=0\)
枚举走多少步横着的,则得方案数
暴力算,\(O(n)\) .
\(typ=1\)
答案是卡特兰数 \(C_n\) .
\(typ=2\)
放递推式:
于是答案是 \(F_{n/2}\) .
\(O(n^2)\) 暴力算即可 .
\(typ=3\)
类似 \(typ=0\),枚举走多少步横着的,则得方案数
Bonus
这个是可以 \(O(n\log n)\) 求一行的 .
首先把模数变成 \(998244353\),比较亲民 .
\(typ=1\) 直接 \(O(n)\) 递推 .
其他情况:
- \(typ=2\):半在线卷积(或者求逆).
- \(typ=0,3\):二项卷积 .
于是就 \(O(n\log n)\) 了,结束 .
upd. 其实任意模数二项卷积的话复杂度大概也是可以干到 \(O(n\log n)\) 的 .
DP搬运工1
牛子 DP
定义 \(dp_{i,j,k}\) 表示已经填了 \([1,i]\),目前有 \(j\) 个空位,max 和为 \(k\) 的方案数 .
转移直接讨论:
- 有空位,直接插进去(e.g. 1304 -> 1324).
- 有空位,插到边上(e.g. 1004 -> 1204).
- 有空位,插到中间(e.g. 1004 -> 10204).
- 直接插到两侧(e.g. 123 -> 4123).
- 插到两侧中间加一空位(e.g. 123 -> 40123).
具体柿子见代码 .
时间复杂度 \(O(n^4)\) .
以下是博客签名,正文无关
本文来自博客园,作者:yspm,转载请注明原文链接:https://www.cnblogs.com/CDOI-24374/p/16503427.html
版权声明:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0)进行许可。看完如果觉得有用请点个赞吧 QwQ