2022-7-25 #17 UR12
最近很摆,很久没更博了。😥😥😥
打各种比赛都不知道为什么一直被虐,太奇怪了。
045 uoj#180. 【UR #12】实验室外的攻防战
比较简单的题,感觉之前在 CF 见过?
模拟冒泡排序的过程,用线段树动态维护区间最小值就好了。
写错好多发,真的蚌埠住。。。
#include<stdio.h>
#define lc(x) (x<<1)
#define rc(x) (x<<1|1)
#define mid (l+r>>1)
const int maxn=100005,maxt=maxn<<2;
int n;
int a[maxn],b[maxn],mn[maxt],p[maxn];
inline int min(int a,int b){
return a<b? a:b;
}
void modify(int l,int r,int now,int p,int v){
if(l==r){
mn[now]=v;
return ;
}
if(p<=mid)
modify(l,mid,lc(now),p,v);
else modify(mid+1,r,rc(now),p,v);
mn[now]=min(mn[lc(now)],mn[rc(now)]);
}
int query(int l,int r,int now,int L,int R){
if(L>R)
return n+1;
if(L<=l&&r<=R)
return mn[now];
int res=n+1;
if(L<=mid)
res=min(res,query(l,mid,lc(now),L,R));
if(mid<R)
res=min(res,query(mid+1,r,rc(now),L,R));
return res;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),p[a[i]]=i,modify(1,n,1,i,a[i]);
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
int pos=p[b[i]];
if(query(1,n,1,1,pos-1)<b[i]){
puts("NO");
return 0;
}
modify(1,n,1,pos,n+1);
}
puts("YES");
return 0;
}
046 uoj#181. 【UR #12】密码锁
也比较简单?
竞赛图强连通分量数量等于割集数量+1。(因为缩点之后是链状的)
不能暴力枚举点集,但是可以发现对于不同特殊边连通块,它们之间的影响是很小的,我们完全可以对于每个连通块枚举点集,最后用背包合并。
复杂度 \(O((n+m)2^m)\)。
#include<stdio.h>
#include<vector>
using namespace std;
const int maxn=40,mod=998244353,inv10000=796898467,inv2=(mod+1)/2;
int n,m,ans,stp,tot,all;
int vis[maxn],f[maxn],mul[maxn*maxn],xx[maxn],yy[maxn],zz[maxn],id[maxn],g[maxn];
vector<int>v[maxn];
void dfs(int x){
vis[x]=stp,id[x]=++tot;
for(int i=0;i<v[x].size();i++)
if(vis[v[x][i]]==0)
dfs(v[x][i]);
}
int main(){
mul[0]=1;
for(int i=1;i<maxn*maxn;i++)
mul[i]=1ll*mul[i-1]*inv2%mod;
scanf("%d%d",&n,&m);
all=1;
for(int i=1;i<=n*(n-1);i++)
all=10000ll*all%mod;
for(int i=1,x,y,z;i<=m;i++)
scanf("%d%d%d",&x,&y,&z),z=1ll*z*inv10000%mod,xx[i]=x,yy[i]=y,zz[i]=z,v[x].push_back(y),v[y].push_back(x);
f[0]=1;
for(int s=1;s<=n;s++)
if(vis[s]==0){
tot=0,stp++,dfs(s);
for(int s=0;s<(1<<tot);s++){
int mul=1;
for(int i=1;i<=m;i++)
if(vis[xx[i]]==stp&&vis[yy[i]]==stp&&((s>>(id[xx[i]]-1))&1)!=((s>>(id[yy[i]]-1))&1)){
if((s>>(id[xx[i]]-1))&1)
mul=2ll*mul*zz[i]%mod;
else mul=2ll*mul*(1-zz[i]+mod)%mod;
}
for(int i=n;i>=__builtin_popcount(s);i--)
g[i]=(g[i]+1ll*mul*f[i-__builtin_popcount(s)])%mod;
}
for(int i=0;i<=n;i++)
f[i]=g[i],g[i]=0;
}
for(int i=0;i<n;i++)
ans=(ans+1ll*f[i]*mul[i*(n-i)])%mod;
printf("%d\n",1ll*ans*all%mod);
return 0;
}
047 uoj#182. 【UR #12】a^-1 + b problem
很经典的处理方法,好像在洛谷月赛 Div2C 中见到过(((
可以发现,每个数 \(x\) 都能表示成 \(\frac{ax+b}{cx+d}\) 形式,其中 \(a,b,c,d\) 是与 \(x\) 无关的系数。
化简可变为 $$p+\frac{q}{x+k}$$,我们只需对于 \(m\) 个 \(k\) 求出 \(\sum_{i=1}^n\frac{1}{a_i+k}\) 即可。
考虑:
\[\sum_{i=1}^n\frac{1}{a_i+k}=\frac{\sum_j\prod_{i\ne j}(a_i+k)}{\prod_{i=1}^n(a_i+k)}
\]
下面是经典多项式多点求值,上面其实就是下面那个多项式求导,同样可以多点求值。
复杂度 \(O(n\log^2 n)\)。
#include<stdio.h>
#include<vector>
#include<assert.h>
#define mid (l+r>>1)
#define lc(x) (x<<1)
#define rc(x) (x<<1|1)
using namespace std;
const int maxk=19,maxn=(1<<maxk),maxN=60005,mod=998244353,G=3,invG=(mod+1)/3;
int n,m,q;
int pt[maxN],ans[maxN],P[maxN],Q[maxN],id[maxN],a[maxn];
int ksm(int a,int b){
int res=1;
for(;b;a=1ll*a*a%mod,b>>=1)
if(b&1)
res=1ll*res*a%mod;
return res;
}
namespace Polynomial{
int btf[maxn],w[maxk+1][maxn][2],inv[maxn];
typedef vector<int>poly;
void init(){
for(int len=2,i=1;i<=maxk;len<<=1,i++){
int omega1=ksm(G,(mod-1)/len),omega2=ksm(invG,(mod-1)/len);
w[i][0][0]=w[i][0][1]=1;
for(int j=1;j<len;j++)
w[i][j][0]=1ll*w[i][j-1][0]*omega1%mod,w[i][j][1]=1ll*w[i][j-1][1]*omega2%mod;
}
inv[1]=1;
for(int i=2;i<maxn;i++)
inv[i]=mod-1ll*(mod/i)*inv[mod%i]%mod;
}
int getlen(int n){
int lim=1,r=0;
while(lim<n)
lim<<=1,r++;
for(int i=0;i<lim;i++)
btf[i]=(btf[i>>1]>>1)|((i&1)<<(r-1));
return lim;
}
void NTT(poly &x,int lim,int opt){
x.resize(lim);
for(int i=0;i<lim;i++)
if(i<btf[i])
swap(x[i],x[btf[i]]);
for(int len=2,now=1,p=1;len<=lim;len<<=1,now<<=1,p++)
for(int i=0;i<lim;i+=len)
for(int j=0;j<now;j++){
int a=x[i+j],b=1ll*x[now+i+j]*w[p][j][opt]%mod;
x[i+j]=(a+b)%mod,x[now+i+j]=(a-b+mod)%mod;
}
if(opt==0)
for(int i=0;i<lim;i++)
x[i]=1ll*x[i]*inv[lim]%mod;
}
poly operator*(poly a,poly b){
int deg=a.size()+b.size()-1,lim=getlen(deg);
poly c(lim);
NTT(a,lim,1),NTT(b,lim,1);
for(int i=0;i<lim;i++)
c[i]=1ll*a[i]*b[i]%mod;
NTT(c,lim,0),c.resize(deg);
return c;
}
poly polyinv(poly x,int deg){
poly res;
if(deg==1){
res.push_back(ksm(x[0],mod-2));
return res;
}
poly a=x,b=polyinv(x,(deg+1)>>1);
a.resize(deg);
int lim=getlen(deg<<1);
NTT(a,lim,1),NTT(b,lim,1);
for(int i=0;i<lim;i++)
res.push_back((2ll*b[i]-1ll*a[i]*b[i]%mod*b[i]%mod+mod)%mod);
NTT(res,lim,0),res.resize(deg);
return res;
}
poly polyrev(poly x){
poly res;
for(int i=x.size()-1;i>=0;i--)
res.push_back(x[i]);
return res;
}
poly polymod(poly a,poly b){
if(b.size()>a.size())
return a;
int n=a.size(),m=b.size();
poly ar=polyrev(a),br=polyrev(b);
br.resize(n-m+2);
poly c=polyinv(br,n-m+2),d=ar*c;
d.resize(n-m+1);
poly q=polyrev(d),bq=b*q;
poly r;
for(int i=0;i<m-1;i++)
r.push_back((a[i]-bq[i]+mod)%mod);
return r;
}
};
using namespace Polynomial;
poly f,g,c[maxN<<2];
poly solve(int l,int r){
if(l==r){
poly res(2);
res[0]=a[l],res[1]=1;
return res;
}
return solve(l,mid)*solve(mid+1,r);
}
void solve1(int l,int r,int now){
if(l==r){
c[now].resize(2),c[now][0]=(mod-pt[l])%mod,c[now][1]=1;
return ;
}
solve1(l,mid,lc(now)),solve1(mid+1,r,rc(now));
c[now]=c[lc(now)]*c[rc(now)];
}
void solve2(int l,int r,int now,poly v,poly w){
v=polymod(v,c[now]),w=polymod(w,c[now]);
if(l==r){
ans[id[l]]=1ll*w[0]*ksm(v[0],mod-2)%mod;
return ;
}
solve2(l,mid,lc(now),v,w),solve2(mid+1,r,rc(now),v,w);
}
int main(){
init();
scanf("%d%d",&n,&m);
int sum=0;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),sum=(sum+a[i])%mod;
int a=1,b=0,c=0,d=1;
for(int i=1,t,x;i<=m;i++){
scanf("%d",&t);
if(t==1)
scanf("%d",&x),a=(a+1ll*x*c)%mod,b=(b+1ll*x*d)%mod;
if(t==2)
swap(a,c),swap(b,d);
if(c){
P[i]=1ll*n*a%mod*ksm(c,mod-2)%mod,Q[i]=1ll*(b-1ll*a*ksm(c,mod-2)%mod*d%mod+mod)*ksm(c,mod-2)%mod;
id[++q]=i,pt[q]=1ll*d*ksm(c,mod-2)%mod;
}
else P[i]=(1ll*sum*a+1ll*n*b)%mod;
}
if(q){
f=solve(1,n),solve1(1,q,1);
g.resize(f.size()-1);
for(int i=1;i<f.size();i++)
g[i-1]=1ll*f[i]*i%mod;
solve2(1,q,1,f,g);
}
for(int i=1;i<=m;i++)
printf("%d\n",(int)((P[i]+1ll*Q[i]*ans[i])%mod));
return 0;
}