VPNOI2025
NewMarchqwq · · 个人记录
含剧透。
没有大样例的 VP。[90,100]+[0,100]+[8,8]+[80,100]+[60,68]+[0,35]。我的评价是 d1t1~d2t1<d2t2<d1t2<d1t3<d2t3,其中两天 t3 的排序不太确定。
还是两天 t2 太慢了。如果都快一个小时,就可能能打到金牌线了……
Day1
2025/7/15 08:30-13:30
起晚了,所以 8:30 开始。
上来看到 t1 会了显然的
t2 开头看错题了,看成了
想了会 t3,不会任何 poly 复杂度。
然后发现看错 t2 题了。发现修补一下就可以了。细节很多,写了两个小时大概到了 12:00。感觉很容易挂。
然后终于发现 t1 自己唐了。过了 t1。
最后 1h,想 t3。发现一点不会 8 分跑路。
题解
T1 考虑把
T2 发现最后一定是分成若干段,每段 [] 或 ==[] 或 []== 或 ==[]==,其中 = 表示 0 [] 表示操作的但是不一定是 0 的数。对这四种 dp 就行了。0 的情况有点细节。
T3 ?
Day2
2025/7/17 08:30-13:30
起早了但是想好好吃早饭,所以还是 8:30。
感觉 t1 极为神秘,但利用小样例找找规律就会了。9:40 左右过了 t1,觉得可能会有点卡常。
推 t2,一直不会。从送的 8 分,改到了 dp 的 16,然后突然会了一个容斥,28。然后再推了推就获得了 B 性质的所有和其他的
t3 在 t1 过了后短暂地想过一会,只会 35,去不掉二分更不会小于平方。过了 t2 写了 35 就结束了。
题解
t1 画一下就发现如果有 110 则找最前面的 110 然后输出 n-i-1,否则如果有 101 输出 1,否则输出 0。
t2 看下面
t3 35 分的贪心是显然的。先二分,然后能用杀换闪一定换(省 cd),如果杀不够了再换回来就行了。
Day 2 t2 题解详细版
为啥要集合幂级数?我连 FWT 都不写(比 FMT 即高位前后缀和差积操作容易错)!
做之前可以先写一个
发现
考虑容斥,求
这个很容易用高维后缀积优化式子,最后长
然后考虑计算
题外话:你注意到上面
考虑更帅的容斥。进行简单的推导发现从
欸现在可以回到原题面了。原题只要求求
现在我们把式子化成了可以或卷积的事情!于是你两次高维前缀和一次高维前缀差,就得到了后面的卷积。枚举
没有 B 性质的时候,可以扩域,存储
代码 2400B。
#include <bits/stdc++.h>
#define rep(i, a, b) for (int i = (a), i##ABRACADABRA = (b); i <= i##ABRACADABRA; i++)
#define drep(i, a, b) for (int i = (a), i##ABRACADABRA = (b); i >= i##ABRACADABRA; i--)
using namespace std;
using ll = long long;
constexpr ll mod=998244353;
ll qpow(ll x, ll y) {
if (y < 0)
y += mod - 1 + mod - 1;
if (x == mod - 1)
return y & 1 ? mod - 1 : 1;
ll res = 1;
for (; y; y >>= 1) {
if (y & 1) {
res *= x;
res %= mod;
}
x *= x;
x %= mod;
}
return res;
}
int caseid;
int n;
ll a[1<<20|5];
struct safe_modint{
ll x;
int c;
safe_modint(ll t=0):x(!t?1:t),c(!t){}
safe_modint(const safe_modint&r):x(r.x),c(r.c){}
safe_modint(ll x,int c):x(x),c(c){}
friend safe_modint operator+(safe_modint p,safe_modint q){return p.c^q.c?(p.c<q.c?p:q):(safe_modint){(p.x+q.x)%mod,p.c};}
friend safe_modint operator-(safe_modint p,safe_modint q){q.x=(mod-q.x)%mod;return p+q;}
friend safe_modint operator*(safe_modint p,safe_modint q){return (safe_modint){p.x*q.x%mod,p.c+q.c};}
safe_modint inv(){return (safe_modint){qpow(x,-1),-c};}
ll val(){assert(c>=0);return c?0:x;}
};
safe_modint sum2[1<<20|5],sum1[1<<20|5],isum1[1<<20|5],X[1<<20|5],Y[1<<20|5],Z[1<<20|5],conv[1<<20|5];
void do_conv(safe_modint*p,safe_modint*r){ // FMT(高位前缀和差) 实现 r=p*p 或卷积
rep(i,0,n-1)rep(j,0,(1<<n)-1)
if (j>>i&1)p[j]=p[j]+p[j^1<<i];
rep(i,0,(1<<n)-1)r[i]=p[i]*p[i];
rep(i,0,n-1)rep(j,0,(1<<n)-1)
if (j>>i&1)r[j]=r[j]-r[j^1<<i];
}
void solve(){
scanf("%d",&n);
rep(i,0,(1<<n)-1)scanf("%lld",&a[i]);
rep(i,0,(1<<n)-1)sum1[i]=(a[i]+1)%mod,sum2[i]=(a[i]+a[i]+1)%mod;
drep(i,n-1,0)drep(j,(1<<n)-1,0)
if (j>>i&1)sum1[j^(1<<i)]=sum1[j^(1<<i)]*sum1[j],sum2[j^1<<i]=sum2[j^1<<i]*sum2[j];
rep(i,0,(1<<n)-1)isum1[i]=sum1[i].inv();
rep(i,0,(1<<n)-1)X[i]=isum1[i]*isum1[i]*sum2[i],Y[i]=sum1[i],Z[i]=Y[i]*qpow(mod-2,__builtin_popcount(i));
// rep(i,0,(1<<n)-1)cout<<Z[i]<<" \n"[i==(1<<n)-1];
do_conv(Z,conv);
// rep(i,0,(1<<n)-1)cout<<conv[i]<<" \n"[i==(1<<n)-1];
safe_modint res=0;
// rep(U,0,(1<<n)-1)rep(V,0,(1<<n)-1)res+=qpow(mod-1,__builtin_popcount(U^V))*qpow(2,__builtin_popcount(U&V))%mod*X[U|V]%mod*Y[U]%mod*Y[V]%mod;
rep(T,0,(1<<n)-1)res=res+X[T]*qpow(2,-__builtin_popcount(T))*conv[T];
printf("%lld\n",res.val());
}
int main() {
int tt;
scanf("%d%d",&caseid,&tt);
while (tt--)solve();
return 0;
}