CSP-S加赛1
A. antipalindrome
真 · 签到题
然后忘了给 取模, 挂了
考虑任何大于 的回文, 必然存在相邻两个字母相同,或者中间隔一个字母,那么从前往后考虑每一个位置,他有 种可选方案
答案就是
code
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
ll qpow(ll x, ll y){
ll ans = 1;
for(; y; y >>= 1, x = x * x % mod)if(y & 1)ans = ans * x % mod;
return ans;
}
ll n, m;
ll work(){
m %= mod;
if(n == 1)return m;
if(n == 2)return m * (m - 1) % mod;
if(m == 1)return 0;
return m * (m - 1) % mod * qpow(m - 2, n - 2) % mod;
}
int main(){
int t; scanf("%d",&t);
for(int ask = 1; ask <= t; ++ask){
scanf("%lld%lld",&n,&m);
printf("%lld\n",work() % mod);
}
return 0;
}
B. ZZH与计数
预处理打挂了, 然后没捞到暴力分...
发现对于一个数 , 它有 位为 , 位为 , 那么对于 中 位为 , 中 位为 的所有数,得到他们的概率是一样的, 可以用数学归纳法证明
进一步扩展,发现对 相同的 到相同的 , , 概率也是一样的
所以我们可以按照 进行处理,得到
然后进行一些 得到答案
先考虑如何求得
发现当 确定时, 从二元组 转移到 的概率是不变的, 于是我们可以用矩阵乘法进行转移,快速幂优化一下
转移矩阵系数,在 时, 有 概率操作, 一共种结果, 其中 种为目标状态,于是这部分系数为
类似的可以得到 的转移系数,这里不再展开
最后从矩阵转存到数组对应位时乘上
对于这部分矩阵乘法,有 个二元组,这是 的矩阵, 每次乘法都是 , 所以一共复杂度
好像有亿点大, 所以优化一下常数, 发现每次使用的数满足 , ,每次只对他们进行标号,不必每次跑 矩阵, 这样我们给它乘上了一个非常小的常数 () 所以复杂度就正确了
再考虑 ,设 表示处理完了前 位, 答案的前 位为 的前 位, 的剩余位是未处理的原始值, 还需要 位原始值为 的位填 , 位原始值为 的填 的期望
初始状态枚举所有数 以及对应的
转移显然
答案就是
忘了粘代码了。。。
code
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int mod = 998244353;
typedef long long ll;
struct matrix{
int n, a[330][330];
void clear(){n = 0; memset(a, 0, sizeof(a));}
matrix(){clear();}
friend matrix operator *(const matrix a, const matrix b){
matrix c; c.n = a.n;
for(int i = 1; i <= c.n; ++i)
for(int k = 1; k <= c.n; ++k){
int ls = a.a[i][k];
for(int j = 1; j <= c.n; ++j)c.a[i][j] = (c.a[i][j] + 1ll * ls * b.a[k][j] % mod) % mod;
}
return c;
}
void gen(int _n){n = _n; for(int i = 1; i <= n; ++i)a[i][i] = 1;}
};
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 ct[150005], ipo[25], n, m, mx, p, ip;
int c[25][25], invc[25][25];
void init(){
int a, b;
scanf("%d%d%d%d",&n,&m,&a,&b);
mx = (1 << n);
ipo[0] = 1; for(int i = 1; i <= n; ++i) ipo[i] = qpow(1 << i, mod - 2);
for(int i = 1; i < mx; ++i)ct[i] = ct[i >> 1] + (i & 1);
for(int i = 0; i <= n; ++i){
c[i][0] = 1; invc[i][0] = 1;
for(int j = 1; j <= i; ++j){
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
invc[i][j] = qpow(c[i][j], mod - 2);
}
}
p = 1ll * a * qpow(b, mod - 2) % mod;
ip = 1ll * (b - a) * qpow(b, mod - 2) % mod;
}
int ans[150005];
int v[150005];
int g[19][19][19];
int f[2][150005][19][19];
int id[17][17];
void work(){
for(int a = 0; a <= n; ++a){
int b = n - a, cnt = 0;
for(int i = 0; i <= a; ++i)
for(int j = 0; j <= b; ++j)
id[i][j] = ++cnt;
matrix mp; mp.n = cnt;
for(int i = 0; i <= a; ++i)
for(int j = 0; j <= b; ++j){
for(int x = 0; x <= i; ++x)
for(int y = 0; y <= j; ++y)
mp.a[id[i][j]][id[x][y]] = (mp.a[id[i][j]][id[x][y]] + 1ll * c[i][x] * c[j][y] % mod * ipo[i + j] % mod * p % mod) % mod;
for(int x = i; x <= a; ++x)
for(int y = j; y <= b; ++y)
mp.a[id[i][j]][id[x][y]] = (mp.a[id[i][j]][id[x][y]] + 1ll * c[a - i][x - i] * c[b - j][y - j] % mod * ipo[n - i - j] % mod * ip % mod) % mod;
}
matrix as; as.gen(cnt);
int lm = m;for(; lm; mp = mp * mp, lm >>= 1)if(lm & 1)as = as * mp;
for(int x = 0; x <= a; ++x)
for(int y = 0; y <= b; ++y)
g[a][x][y] = 1ll * as.a[id[a][0]][id[x][y]] * invc[a][x] % mod * invc[b][y] % mod;
}
for(int i = 0; i < mx; ++i){
for(int a = 0; a <= ct[i]; ++a){
for(int b = 0; b <= n - ct[i]; ++b){
f[0][i][a][b] = 1ll * g[ct[i]][a][b] * v[i] % mod;
}
}
}
for(int i = 0; i < n; ++i){
for(int s = 0; s < mx; ++s){
for(int a = 0; a <= n; ++a){
for(int b = 0; b <= n - a; ++b){
if(f[i & 1][s][a][b]){
int now = f[i & 1][s][a][b];
if(s & (1 << i)){
if(a)f[(i + 1) & 1][s][a - 1][b] = (f[(i + 1) & 1][s][a - 1][b] + now) % mod;
f[(i + 1) & 1][s xor (1 << i)][a][b] = (f[(i + 1) & 1][s xor (1 << i)][a][b] + now) % mod;
}else{
if(b)f[(i + 1) & 1][s | (1 << i)][a][b - 1] = (f[(i + 1) & 1][s | (1 << i)][a][b - 1] + now) % mod;
f[(i + 1) & 1][s][a][b] = (f[(i + 1) & 1][s][a][b] + now) % mod;
}
f[i & 1][s][a][b] = 0;
}
}
}
}
}
for(int i = 0; i < mx; ++i)ans[i] = f[n & 1][i][0][0];
}
int main(){
init(); for(int i = 0; i < mx; ++i)scanf("%d",&v[i]);
work(); for(int i = 0; i < mx; ++i)printf("%d ",ans[i]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】