来自学长的馈赠2
A. 随
开桶,然后就是乘
正解用什么多项式的思路考虑,但其实是个快速幂优化
发现开桶后就是一个特定乘法,满足结合率交换律,所以直接快速幂优化
code
#include<cstdio>
#include<cstring>
using namespace std;
const int MOD = 1e9 + 7;
const int maxn = 100005;
int n, m, mod;
int a[maxn],cnt[maxn],now[maxn],ls[maxn];
int qpow(int x,int y){
int ans = 1;
for(; y; y >>= 1, x = 1ll * x * x % MOD)if(y & 1)ans = 1ll * ans * x % MOD;
return ans;
}
void mul(int x[],int y[]){
for(int i = 1; i < mod; ++i)ls[i] = 0;
for(int i = 1; i < mod; ++i)
if(x[i])
for(int j = 1; j < mod; ++j)
if(y[j])ls[i * j % mod] = (ls[i * j % mod] + 1ll * x[i] * y[j] % MOD) % MOD;
for(int i = 1; i < mod; ++i)x[i] = ls[i];
}
void qpow(int y){
now[1] = 1;
for(; y; y >>= 1){
if(y & 1)mul(now, cnt);
mul(cnt, cnt);
}
}
int main(){
scanf("%d%d%d",&n, &m, &mod);
for(int i = 1; i <= n; ++i)scanf("%d", &a[i]);
for(int i = 1; i <= n; ++i)++cnt[a[i]];
qpow(m);
int ans = 0;
for(int i = 1; i < mod; ++i)ans = (ans + 1ll * now[i] * i % MOD) % MOD;
ans = 1ll * ans * qpow(qpow(n, m), MOD - 2) % MOD;
printf("%d\n",ans);
return 0;
}
B. 单
原题, https://www.cnblogs.com/Chencgy/p/16313022.html
又打了一遍
code
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e5 + 5;
typedef long long ll;
int n, head[maxn], tot;
struct edge{
int to,net;
}e[maxn << 1 | 1];
void add(int u, int v){
e[++tot].net = head[u];
head[u] = tot;
e[tot].to = v;
}
ll rd[maxn], ot[maxn], dep[maxn], fa[maxn];
ll s[maxn];
void dfs_1(int x){
for(int i = head[x]; i; i = e[i].net){
int v = e[i].to;
if(v == fa[x])continue;
fa[v] = x;
dfs_1(v);
}
}
void ga(int x){
ot[x] = s[x];
for(int i = head[x]; i; i = e[i].net){
int v = e[i].to;
if(v == fa[x])continue;
ot[x] -= s[v];
ga(v);
}
}
void work_a(){
dfs_1(1);
ll sum = 0;
for(int i = 2; i <= n; ++i)sum += rd[i] - rd[fa[i]];
sum += rd[1];sum += rd[1];
s[1] = sum / (n - 1);
for(int i = 2; i <= n; ++i)s[i] = (s[1] + rd[fa[i]] - rd[i]) / 2;
ga(1);
}
void dfs(int x, int fa){
s[x] = rd[x];
for(int i = head[x]; i; i = e[i].net){
int v = e[i].to;
if(v == fa)continue;
dep[v] = dep[x] + 1;
dfs(v, x);
s[x] += s[v];
}
}
void dp(int x,int fa){
for(int i = head[x]; i; i = e[i].net){
int v = e[i].to;
if(v == fa)continue;
ot[v] = ot[x] - s[v] - s[v] + s[1];
dp(v, x);
}
}
void work_b(){
dfs(1, 1);
ot[1] = 0;
for(int i = 1; i <= n; ++i)ot[1] += dep[i] * rd[i];
dp(1, 1);
}
int main(){
int T;scanf("%d", &T);
for(int ask = 1; ask <= T; ++ask){
scanf("%d",&n);
for(int i = 1; i <= n; ++i)head[i] = 0;
tot = 0;
for(int i = 1; i < n; ++i){
int u, v; scanf("%d%d", &u,&v);
add(u,v);add(v,u);
}
int tp;scanf("%d",&tp);
for(int i = 1; i <= n; ++i)scanf("%lld",&rd[i]);
if(tp)work_a();
else work_b();
for(int i = 1; i <= n; ++i)printf("%lld ",ot[i]);
printf("\n");
}
return 0;
}
C. 题
选向上向右,选向上向左,交集为上,各自的为左/右,并集的补集为下
卡特兰数
小,枚举歩走与之前不同的轴
初始因为开始可能走横轴也可能走纵轴
枚举横向步数和纵向步数
然后两个卡特兰乘起来即可
code
#include<cstdio>
#include<cstring>
using namespace std;
const int mod = 1e9 + 7;
const int maxn = 100000 + 5;
int qpow(int x,int y){
int ans = 1;
for(; y; y >>= 1, x = 1ll * x * x % mod)if(y & 1)ans = 1ll * ans * x % mod;
return ans;
}
int fac[maxn], inv[maxn];
void pre(int n){
fac[0] = 1;
for(int i = 1; i <= n; ++i)fac[i] = 1ll * fac[i - 1] * i % mod;
inv[n] = qpow(fac[n], mod - 2);
for(int i = n - 1; i; --i)inv[i] = 1ll * inv[i + 1] * (i + 1) % mod;
inv[0] = 1;
}
int c(int n, int m){return 1ll * fac[n] * inv[m] % mod * inv[n - m] % mod;}
int work_0(int n){
return 1ll * c(n, n / 2) * c(n, n / 2) % mod;
}
int work_1(int n){
return (0ll + c(n, n / 2) - c(n, n / 2 - 1) + mod) % mod;
}
int f[maxn];
int work_2(int n){
f[0] = 2;
for(int i = 2; i <= n; i += 2)
for(int j = 0; j < i; j += 2)
f[i] = (f[i] + 1ll * c(i - j, (i - j) / 2) * f[j] % mod) % mod;
return f[n];
}
int work_3(int n){
int ans = 0;
for(int i = 0; i <= n; i += 2)ans = (ans + 1ll * c(n, i) * work_1(i) % mod * work_1(n - i) % mod) % mod;
return ans;
}
int main(){
int n, tp;
scanf("%d%d",&n, &tp);
pre(n);
switch(tp){
case 0: printf("%d\n",work_0(n));break;
case 1: printf("%d\n",work_1(n));break;
case 2: printf("%d\n",work_2(n));break;
case 3: printf("%d\n",work_3(n));break;
}
return 0;
}
D. DP搬运工1
这个题告诉我一个好的状态设计是多么重要
表示前个数,有个连续段,相邻和为
转移显然
考场状态设计有问题,复杂度爆炸而且还错了。。。
code
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int mod = 998244353;
const int maxn = 51;
int n, K;
int f[maxn][maxn][maxn * maxn];
int main(){
scanf("%d%d",&n, &K);
f[1][1][0] = 1;
for(int i = 1 ; i < n; ++i){
for(int j = 1; j <= i; ++j){
for(int k = 0 ; k <= K; ++k){
if(f[i][j][k]){
f[i + 1][j + 1][k] = (f[i + 1][j + 1][k] + f[i][j][k]) % mod;
f[i + 1][j][k + i + 1] = (f[i + 1][j][k + i + 1] + 1ll * 2 * j * f[i][j][k] % mod) % mod;
f[i + 1][j - 1][k + i + 1 + i + 1] = (f[i + 1][j - 1][k + i + 1 + i + 1] + 1ll * j * (j - 1) * f[i][j][k] % mod) % mod;
}
}
}
}
ll ans = 0;
for(int k = 0; k <= K; ++k) ans += f[n][1][k];
printf("%lld\n",ans % mod);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】