冲刺清北营 5

尝试了雀巢燃魂,感觉比较偏功能性导致豆似乎不是很好。虽然说咖啡因已经对我没什么太大作用了导致功能性也打折扣。咖啡可能会让你从醒着变成想睡觉,但是绝对不会让你从想睡觉的状态醒过来。等退役了以后有时间写个关于我喝过的咖啡的杂论。参考 joke3579 的意见是极好的。

乌蒙大象好像是大前天更新?

吃粮

\(dp_{x}\) 为从 \(x\) 开始随机游走到任意一个叶子的期望时间,则:

  1. 对于叶子:\(dp_x=a_x\)
  2. 对于非叶子:\(dp_x=a_x+\dfrac 1{d_x}\sum_vdp_v\)

按照 [PKUWC2018]随机游走 的套路,设 \(dp_x=k_xdp_{fa_x}+b_x\),然后把后边的 \(dp_v\) 拆成 \(dp_{fa_x}\)\(\sum dp_{son_x}\)。于是得到

\[k_x=\frac 1{d_x-\sum k_{son_x}} b_x=\frac{d_xa_x+\sum b_{son_x}}{d_x-\sum k_{son_x}} \]

由于 \(1\) 没有父亲,所以答案就是 \(b_1\)

然后看每次修改的影响:对于非叶子的贡献是从该节点到根的 \(k\) 的乘积乘上 \(d_xa_x\),对于叶子的贡献则是从该节点父亲到根的 \(k\) 的乘积乘上 \(d_xa_x\)。于是 dfs 两边得到每个节点贡献就可以 \(O(1)\) 修改了。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <cstring>
using namespace std;
const int mod=998244353;
int qpow(int a,int b){
    int ans=1;
    while(b){
        if(b&1)ans=1ll*ans*a%mod;
        a=1ll*a*a%mod;
        b>>=1;
    }
    return ans;
}
struct node{
    int v,next;
}edge[200010];
int n,t,head[100010];
void add(int u,int v){
    edge[++t].v=v;edge[t].next=head[u];head[u]=t;
}
int d[100010],k[100010],b[100010],a[100010];
void dfs1(int x,int f){
    if(d[x]==1){
        k[x]=0;b[x]=a[x];return;
    }
    int sumk=0,sumb=0;
    for(int i=head[x];i;i=edge[i].next){
        if(edge[i].v!=f){
            dfs1(edge[i].v,x);
            sumk=(sumk+k[edge[i].v])%mod;
            sumb=(sumb+b[edge[i].v])%mod;
        }
    }
    sumk=(d[x]-sumk+mod)%mod;
    sumk=qpow(sumk,mod-2);
    sumb=(sumb+1ll*d[x]*a[x])%mod;
    k[x]=sumk;b[x]=1ll*sumb*sumk%mod;
}
int val[100010];
void dfs2(int x,int f){
    if(d[x]==1){
        val[x]=val[f];return;
    }
    val[x]=1ll*val[f]*k[x]%mod;
    for(int i=head[x];i;i=edge[i].next){
        if(edge[i].v!=f)dfs2(edge[i].v,x);
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<n;i++){
        int u,v;scanf("%d%d",&u,&v);
        add(u,v);add(v,u);d[u]++;d[v]++;
    }
    val[0]=1;
    dfs1(1,0);dfs2(1,0);
    int ans=b[1];
    printf("%d\n",ans);
    int q;scanf("%d",&q);
    while(q--){
        int x,y;scanf("%d%d",&x,&y);
        ans=(ans-1ll*val[x]*d[x]%mod*a[x]%mod+mod)%mod;
        a[x]=y;
        ans=(ans+1ll*val[x]*d[x]%mod*a[x])%mod;
        printf("%d\n",ans);
    }
    return 0;
}

平衡

首先第一步 tarjan 缩点。然后每个连通块的代价是个下凸包。

然后不知道为啥要分治,但是分治了。考虑分治到当前层的图的最小权闭合子图,一定存在一种方案使所有点权 \(\ge mid\)。于是每次跑最小割分成两半左右递归。不知道为啥是对的。

实际上不用缩点。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int inf=0x3f3f3f3f;
vector<int>g[510];
struct node{
    int v,w,next;
}edge[2000010];
int n,m1,m2,S,T,t,head[510];
void Add(int u,int v,int w){
    edge[++t].v=v;edge[t].w=w;edge[t].next=head[u];head[u]=t;
}
void add(int u,int v,int w){
    Add(u,v,w);Add(v,u,0);
}
int a[510],ans[510],id[510];
int head2[510],dis[510];
bool vis[510];
queue<int>q;
bool bfs(int st){
    for(int i=0;i<=T;i++)head2[i]=head[i],dis[i]=0;
    dis[st]=1;q.push(st);
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int i=head[x];i;i=edge[i].next){
            if(edge[i].w&&!dis[edge[i].v]){
                dis[edge[i].v]=dis[x]+1;
                if(edge[i].v==T){
                    while(!q.empty())q.pop();
                    return true;
                }
                q.push(edge[i].v);
            }
        }
    }
    return false;
}
int dfs(int x,int flow){
    if(x==T)return flow;
    int sum=0;
    for(int &i=head2[x];i;i=edge[i].next){
        if(edge[i].w&&dis[edge[i].v]==dis[x]+1){
            int ret=dfs(edge[i].v,min(flow,edge[i].w));
            if(ret){
                edge[i].w-=ret;edge[i^1].w+=ret;
                flow-=ret;sum+=ret;
                if(!flow)break;
            }
            else dis[edge[i].v]=-1;
        }
    }
    return sum;
}
void get(int x){
    vis[x]=true;
    for(int i=head[x];i;i=edge[i].next){
        if(edge[i].w&&!vis[edge[i].v])get(edge[i].v);
    }
}
void solve(int l,int r,vector<int>p){
    if(p.empty())return;
    if(l==r){
        for(int x:p)ans[x]=l;
        return;
    }
    int mid=(l+r)>>1;
    S=p.size();T=p.size()+1;t=1;
    for(int i=0;i<=T;i++)head[i]=0,vis[i]=false;
    for(int i=0;i<p.size();i++)id[p[i]]=i+1;
    for(int i=0;i<p.size();i++){
        if(a[p[i]]>mid)add(S,i,1);
        else add(i,T,1);
        for(int v:g[p[i]])if(id[v])add(i,id[v]-1,inf);
    }
    for(int x:p)id[x]=0;
    while(bfs(S))dfs(S,inf);
    get(S);
    vector<int>L,R;
    for(int i=0;i<p.size();i++){
        if(!vis[i])L.push_back(p[i]);
        else R.push_back(p[i]);
    }
    solve(l,mid,L);solve(mid+1,r,R);
}
int main(){
    scanf("%d%d%d",&n,&m1,&m2);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=m1;i++){
        int u,v;scanf("%d%d",&u,&v);
        g[u].push_back(v);g[v].push_back(u);
    }
    for(int i=1;i<=m2;i++){
        int u,v;scanf("%d%d",&u,&v);
        g[u].push_back(v);
    }
    vector<int>p;
    for(int i=1;i<=n;i++)p.push_back(i);
    solve(0,1e9,p);
    long long val=0;
    for(int i=1;i<=n;i++)val=(val+abs(a[i]-ans[i]));
    printf("%lld\n",val);
    return 0;
}

枸杞

蚌埠。懒得写了,直接粘题解。

依题解模拟即可。这题卡常,矩阵开 unsigned long long 然后矩阵乘的第三层改成乘一半取一次模即可。详见代码。

第三条命题咋证?

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <cstring>
#include <unordered_map>
#define int long long
using namespace std;
typedef vector<int> poly;
const int mod=998244353;
int read(){
    int x=0;char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))x=(10ll*x+ch-'0')%mod,ch=getchar();
    return x;
}
void print(int x){
    if(x>=10)print(x/10);
    putchar(x%10+'0');
}
int n,m,wl,w[50010],jc[50010],inv[50010];
void get(int n){wl=1;while(wl<n)wl<<=1;}
#define add(x,y) (x+y>=mod?x+y-mod:x+y)
#define sub(x,y) (x<y?x-y+mod:x-y)
int qpow(int a,int b){
    int ans=1;
    while(b){
        if(b&1)ans=1ll*ans*a%mod;
        a=1ll*a*a%mod;
        b>>=1;
    }
    return ans;
}
void init(int n){
    int t=1;
    while((1<<t)<n)t++;
    t=min(t-1,21ll);
    w[0]=1;w[1<<t]=qpow(31,1<<21-t);jc[0]=inv[0]=inv[1]=1;
    for(int i=t;i>=1;i--)w[1<<i-1]=1ll*w[1<<i]*w[1<<i]%mod;
    for(int i=1;i<(1<<t);i++)w[i]=1ll*w[i&i-1]*w[i&-i]%mod;
    for(int i=2;i<=n;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
    for(int i=1;i<=n;i++)jc[i]=1ll*jc[i-1]*i%mod,inv[i]=1ll*inv[i-1]*inv[i]%mod;
}
inline void DIF(poly &a){
    int n=a.size();
    for(int mid=n>>1;mid;mid>>=1){
        for(int i=0,k=0;i<n;i+=mid<<1,k++){
            for(int j=0;j<mid;j++){
                int x=a[i+j],y=1ll*a[i+j+mid]*w[k]%mod;
                a[i+j]=add(x,y);a[i+j+mid]=sub(x,y);
            }
        }
    }
}
inline void DIT(poly &a){
    int n=a.size();
    for(int mid=1;mid<n;mid<<=1){
        for(int i=0,k=0;i<n;i+=mid<<1,k++){
            for(int j=0;j<mid;j++){
                int x=a[i+j],y=a[i+j+mid];
                a[i+j]=add(x,y);a[i+j+mid]=1ll*sub(x,y)*w[k]%mod;
            }
        }
    }
    for(int i=1;i<=(n-1)>>1;i++)swap(a[i],a[n-i]);
    int inv=qpow(n,mod-2);
    for(int i=0;i<n;i++)a[i]=1ll*a[i]*inv%mod;
}
struct node{
    unsigned long long a[31][31];
    node(){memset(a,0,sizeof(a));}
    node operator*(const node&s)const{
        node ret;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                for(int k=1;k<=(n>>1);k++)ret.a[i][j]=ret.a[i][j]+a[i][k]*s.a[k][j];
                ret.a[i][j]%=mod;
                for(int k=(n>>1)+1;k<=n;k++)ret.a[i][j]=ret.a[i][j]+a[i][k]*s.a[k][j];
                ret.a[i][j]%=mod;
            }
        }
        return ret;
    }
}gra,F[101],G[101];
const int sq=100,K=10000;
int tr[21][K+10],ans[21][21][K+10];
int getpow(int pw){
    unsigned long long ans=0;
    for(int i=1;i<=n;i++){
        for(int k=1;k<=(n>>1);k++)ans=ans+F[pw%sq].a[i][k]*G[pw/sq].a[k][i];
        ans%=mod;
        for(int k=(n>>1)+1;k<=n;k++)ans=ans+F[pw%sq].a[i][k]*G[pw/sq].a[k][i];
        ans%=mod;
    }
    return ans;
}
void prework(int x){
    n=read();m=read();
    for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)gra.a[i][j]=0;
    for(int i=1;i<=m;i++){
        int u=read(),v=read();gra.a[u][v]=gra.a[v][u]=1;
    }
    for(int i=1;i<=n;i++)gra.a[i][i]=F[0].a[i][i]=G[0].a[i][i]=1;
    for(int i=1;i<=sq;i++)F[i]=F[i-1]*gra;
    G[1]=F[100];
    for(int i=1;i<=sq;i++)G[i]=G[i-1]*G[1];
    for(int i=0;i<=K;i++)tr[x][i]=getpow(i);
}
signed main(){
    int T=read();init(K+1<<1);
    for(int i=1;i<=T;i++)prework(i);
    get(K+1<<1);
    poly g(wl);
    for(int i=0;i<=K;i++)g[i]=(i&1)?mod-inv[i]:inv[i];
    DIF(g);
    static int val[10010];
    for(int i=1;i<=T;i++){
        for(int j=0;j<=K;j++)val[j]=1;
        for(int j=i;j<=T;j++){
            for(int k=0;k<=K;k++)val[k]=1ll*val[k]*tr[j][k]%mod;
            poly f(wl);
            for(int k=0;k<=K;k++)f[k]=1ll*val[k]*inv[k]%mod;
            DIF(f);for(int k=0;k<wl;k++)f[k]=1ll*f[k]*g[k]%mod;DIT(f);
            for(int k=1;k<=K;k++)ans[i][j][k]=(ans[i][j][k-1]+1ll*jc[k]*f[k])%mod;
        }
    }
    int q=read();
    while(q--){
        int l=read(),r=read(),k=read();
        print(ans[l][r][k]),putchar('\n');
    }
    return 0;
}
posted @ 2023-04-24 17:57  gtm1514  阅读(17)  评论(0编辑  收藏  举报