ARC 杂题

ARC150C Path and Subsequence

考试题削弱版。

给你一个无向图,点 \(i\) 有点权 \(v_i\)。给你一个长为 \(k\) 的序列 \(b\),求 \(1\to n\) 的所有路径是否全部包含子序列 \(b\)

\(k\le n,m\le 10^5\)

枚举 \(b_i\),从 \(1\) 开始,将所有不经过点权为 \(b_i\) 的点打上标记(时间戳) \(i\),接下来再对没经过的点往下跑。若 \(n\) 的时间戳为 \(k\) 则说明包含了。时间复杂度 \(O(n+m+k)\)

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=5e5+3;
int n,m,s;
vector<int>e[maxn];
queue<int>q,p;
int vis[maxn];
int c[maxn],b[maxn];
void dfs(int u,int t){
    for(int v:e[u]){
        if(vis[v]==-1){
            vis[v]=t;
            if(c[v]!=b[t+1]){
                dfs(v,t);
            }else{
                p.push(v);
            }
        }
    }
}
signed main(){
    ios::sync_with_stdio(0);
    cin>>n>>m>>s;
    for(int i=1,u,v;i<=m;i++){
        cin>>u>>v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    for(int i=1;i<=n;i++) cin>>c[i],vis[i]=-1;
    for(int i=1;i<=s;i++) cin>>b[i];
    e[0].push_back(1);
    vis[0]=0;
    q.push(0);
    for(int i=0;i<=s;i++){
        while(!q.empty()){
            int j=q.front();
            q.pop();
            vis[j]=i;
            dfs(j,i);
        }
        q=p;
        while(!p.empty()) p.pop();
    }
    if(vis[n]==s) cout<<"Yes";
    else cout<<"No";
    return 0;
}

ARC185E Adjacent GCD

给你一个数列 \(a\),对于每个 \(m\in [1,n]\),求对于每个 \(a_{[1,m]}\) 的子序列 \(S\) 相邻两项的 GCD 的和的和。

\(n\le 5\times 10^5,a_i\le 10^5\)

\(f(i)\) 为以 \(i\) 结尾的答案。则 \(f(i)\) 的答案可以由选/不选 \(i\) 继承过来,再计算从每个 \(j<i\) 转移过来的系数即可,即

\[f(i)=2f(i-1)+\sum\limits_{j<i} 2^{j-1} \gcd(a_i,a_j) \]

由于有 \(\gcd(a_i,a_j)=\sum\limits_{d\mid \gcd(a_i,a_j)} \varphi(d)=\sum\limits_{d} [d\mid a_i][d\mid a_j]\varphi(d)\),所以

\[f(i)=2f(i-1)+\sum\limits_{j<i} 2^{j-1} \sum\limits_{d} [d\mid a_i][d\mid a_j]\varphi(d) \]

把与 \(j\) 无关的往前扔

\[f(i)=2f(i-1)+\sum\limits_{d\mid a_i} \varphi(d)\sum\limits_{j<i} 2^{j-1} [d\mid a_j] \]

\(g(d,i)=\sum\limits_{j<i} 2^{j-1} [d\mid a_j]\),显然这一坨可以 \(O(d(a_i))\) 动态维护,考虑每次加入 \(a_i\) 统计完当前答案后,就在 \(d\mid a_i\) 的位置加上 \(2^{i-1}\) 的贡献即可。

所以最后的式子就是 \(f(i)=2f(i-1)+\sum\limits_{d\mid a_i} \varphi(d) g(d,i)\),时间复杂度 \(O(nd(n))\)

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=5e5+7;
const int mod=998244353;
int n;
int a[maxn];
int f[maxn],g[maxn],po2[maxn],k[maxn],val[maxn];
vector<int>v[maxn];
signed main(){
    cin>>n;
    po2[0]=1;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        po2[i]=po2[i-1]*2%mod;
    }
    for(int i=1;i<=100000;i++){
        k[i]+=i; v[i].emplace_back(i);
        for(int j=2*i;j<=100000;j+=i){
            k[j]-=k[i];
            v[j].emplace_back(i);
        }
    }
    for(int x=1;x<=n;x++){
        f[x]=2*f[x-1];
        for(int d:v[a[x]]){
            f[x]=(f[x]+k[d]*val[d]%mod)%mod;
            val[d]=(val[d]+po2[x-1])%mod;
        }
        cout<<f[x]<<'\n';
    }
    return 0;
}

ARC183C Not Argmax

求满足 \(m\) 个形如【\([l_i,r_i]\) 中最大值的不为 \(p_{x_i}\)】的排列 \(p\) 的数量。

\(n\le 500,m\le 2\times 10^5\)

考虑没有限制时怎么 DP,设 \(f(l,r)\) 表示 \([l,r]\) 的答案,枚举区间内最大值的位置,则有

\[f(l,r)=\sum\limits_{k=l}^r f(l,k-1)f(k+1,r)\binom{r-l}{k-l} \]

加上限制即记个标记 \(t(l,r,k)\),当满足标记时不转移即可,注意转移顺序。标记转移为 \(t(l,r,k)|=t(l+1,r,k)|t(l,r-1,k)\)。时间复杂度 \(O(n^3+m)\)

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=507;
const int maxm=2e5+7;
const int mod=998244353;
int n,m;
int f[maxn][maxn],fac[maxn],ifac[maxn];
bitset<maxn>is[maxn][maxn];
int qpow(int a,int b){
    int res=1;
    for(;b;b>>=1,a=a*a%mod) if(b&1) res=res*a%mod;
    return res;
}
int C(int a,int b){
    if(a<b) return 0;
    return fac[a]*ifac[a-b]%mod*ifac[b]%mod;
}
signed main(){
    cin>>n>>m;
    for(int i=1,l,r,x;i<=m;i++){
        cin>>l>>r>>x;
        is[l][r][x]=1;  
        if(l==r){
            cout<<"0\n";
            return 0;
        }
    }
    for(int len=2;len<=n;len++)
        for(int l=1;l+len-1<=n;l++){
            int r=l+len-1;
            is[l][r]|=is[l+1][r];
            is[l][r]|=is[l][r-1];
        }
    fac[0]=1;
    for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;
    ifac[n]=qpow(fac[n],mod-2);
    for(int i=n-1;~i;i--) ifac[i]=ifac[i+1]*(i+1)%mod; 
    f[1][0]=1;
    for(int i=1;i<=n;i++) f[i][i]=f[i+1][i]=1;
    for(int len=2;len<=n;len++)
        for(int l=1;l+len-1<=n;l++){
            int r=l+len-1;
            for(int k=l;k<=r;k++) if(!is[l][r][k])
                f[l][r]=(f[l][r]+f[l][k-1]*f[k+1][r]%mod*C(r-l,k-l)%mod)%mod;
        }
    cout<<f[1][n];
    return 0;
}
posted @ 2024-11-01 15:19  view3937  阅读(1)  评论(0编辑  收藏  举报
Title