ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

NOIP提高组模拟赛加1

2022-05-26 12:33:26  阅读:136  来源: 互联网

标签:const NOIP int sum fa 赛加 maxn include 模拟


A. 哪一天她能重回我身边

学网络瘤学傻了,用费用瘤搞掉第一问就在想怎么搞方案,然后越想越偏。。。。。

不仅没有搞出来第二问,而且费用瘤的复杂度。。。。

总之就是挂的很惨。。。。

这题居然是个树形\(DP\)???

把背面的数向正面的数连边,翻一张卡相当于把边反向,我们要用最少次数让所有点入度小于等于\(1\),并且求出方案数

显然对每个联通块可以分开考虑

如果一个联通块\(n>m\)那么无论如何都无法满足要求

那么我们只需要考虑\(n==m\)和\(n-1==m\)两种情况

\(n-1==m\)这不是棵树吗

我们再看一眼目的“用最少次数让所有点入度小于等于\(1\)”

在树上就有且只有一个点入度为\(0\),我们令这个点为树根,然后换根\(DP\)就好了

\(n==m\)基环树,环上要么顺时针要么逆时针,其实只有两种情况,随便找个环上的边断开,分别以两边为根\(DFS\)一次即可

最小次数是所有联通块最小次数和,方案数是所有联通块方案数乘起来。

基环树那里有点小细节。。

code
#include<cstdio>
#include<cstring>

using namespace std;

const int mod=998244353;
const int maxn=200005;
const int inf=0x3f;
int n,head[maxn],tot;
struct edge{int net,to,val;}e[maxn<<1|1];
bool vis[maxn];
void add(int u,int v,int w){
    e[++tot].net=head[u];
    head[u]=tot;
    e[tot].to=v;
    e[tot].val=w;
}
void link(int u,int v){
    add(u,v,1);add(v,u,0);
}
int cnt1,cnt2;
void dfs(int x){
    vis[x]=1;++cnt1;
    for(int i=head[x];i;i=e[i].net){
        int v=e[i].to;++cnt2;
        if(vis[v])continue;
        dfs(v);
    }
}
int jh;

void DFS(int x,int fa){
    bool flag=0;vis[x]=1;
    for(int i=head[x];i;i=e[i].net){
        int v=e[i].to;
        if(v==x)jh=i;
        if(v==fa){
            if(flag)jh=i;
            else flag=1;
        }else{
            if(vis[v])jh=i;
            else DFS(v,x);
        }
    }
}

int mi,cnt;
void TD_1(int x,int fa,int s1,int s2){
    for(int i=head[x];i;i=e[i].net){
        int v=e[i].to;
        if(v==fa||i==s1||i==s2)continue;
        if(e[i].val==0)++mi;
        TD_1(v,x,s1,s2);
    }
}
int now;
void TD_2(int x,int fa){
    if(now<mi)mi=now,cnt=0;
    if(now==mi)++cnt;
    for(int i=head[x];i;i=e[i].net){
        int v=e[i].to;
        if(v==fa)continue;
        if(e[i].val==1){
            ++now;TD_2(v,x);--now;
        }else{
            --now;TD_2(v,x);++now;
        }
    }
}

int main(){
    int T;scanf("%d",&T);
    for(int ask=1;ask<=T;++ask){
        tot=0;for(int i=1;i<=n+n;++i)head[i]=0;
        scanf("%d",&n);
        for(int i=1;i<=n;++i){
            int u,v;scanf("%d%d",&u,&v);link(v,u);
        }
        bool flag=1;
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n+n;++i)
            if(!vis[i]){
                cnt1=cnt2=0;
                dfs(i);
                cnt2/=2;
                if(cnt2>cnt1){flag=0;break;}
            }
        if(!flag)printf("-1 -1\n");
        else{
            long long ans2=1;int ans1=0;
            memset(vis,0,sizeof(vis));
            for(int i=1;i<=n+n;++i){
                if(head[i]==0||vis[i])continue;
                jh=0;DFS(i,i);
                if(jh){
                    int u=e[jh].to,v,hj;
                    if(jh%2)hj=jh+1;else hj=jh-1;
                    v=e[hj].to;
                    if(e[jh].val==0){u^=v;v^=u;u^=v;}
                    mi=0;TD_1(u,u,jh,hj);int r1=mi;
                    mi=1;TD_1(v,v,jh,hj);
                    if(r1==mi)ans2=ans2*2%mod;
                    ans1+=r1>mi?mi:r1;
                }else{
                    mi=0;TD_1(i,i,0,0);
                    now=mi;cnt=0;TD_2(i,i);
                    ans2=ans2*cnt%mod;
                    ans1=ans1+mi;
                }    
            }
            printf("%d %lld\n",ans1,ans2);
        }
    }
    return 0;
}

考场推柿子,乱搞半天激动地发现解出了\(S\),赶快实现,,,然后浮点数例外??

仔细观察,大概就是搞了半天整出的柿子是\(0*S=0\),解个毛线。。。

首先知道\(a\)求\(b\),一个简单的树形\(DP\)

令\(S_i\)表示以\(i\)为根的子树所有权值的和,整棵树的根为\(1\)

从\(DP\)中我们可以得到\(b_i=b_{fa}-S_i-S_i+S_1\),这个显然是反推的关键

我们可以得到

\(b_i-b_{fa}=S_1-2*S_i\)

错误搞法\(0=0\)就不说了。。

正解考虑

\(\sum_{i=2}^{n}b_i-b_{i->fa}=(n-1)*S_1-2*\sum_{i=2}^{n}S_i\)

然后我们再想想当初是怎么求\(b_1\)的,你会发现\(b_1=\sum_{i=2}^{n}S_i\)

那么\(\sum_{i=2}^{n}b_i-b_{i->fa}=(n-1)*S_1-2*b_1\)

这里可以解出\(S_1\),然后剩下的就非常简单了

code
#include<cstdio>
#include<cstring>

using namespace std;
#define int long long
const int maxn=100000;
int head[maxn],tot,n;
struct edge{int to,net;}e[maxn<<1|1];
void add(int u,int v){
    e[++tot].net=head[u];
    head[u]=tot;
    e[tot].to=v;
}

int re[maxn],pr[maxn],s[maxn],dep[maxn],dt[maxn];

void DFS(int x,int fa){
    if(x!=1)dt[x]=re[x]-re[fa];
    for(int i=head[x];i;i=e[i].net){
        int v=e[i].to;
        if(v==fa)continue;
        DFS(v,x);
    }
}
void DP(int x,int fa){
    pr[x]=s[x];
    for(int i=head[x];i;i=e[i].net){
        int v=e[i].to;
        if(v==fa)continue;
        DP(v,x);
        pr[x]-=s[v];
    }
}
void worka(){
    for(int i=1;i<=n;++i)pr[i]=0;
    for(int i=1;i<=n;++i)dt[i]=0;
    for(int i=1;i<=n;++i)s[i]=0;
    DFS(1,1);
    for(int i=2;i<=n;++i)s[1]+=dt[i];
    s[1]+=re[1]+re[1];
    s[1]/=(n-1);
    for(int i=2;i<=n;++i)s[i]=(s[1]-dt[i])/2;
    DP(1,1); 
}

void dfs(int x,int fa){
    s[x]+=re[x];
    for(int i=head[x];i;i=e[i].net){
        int v=e[i].to;
        if(v==fa)continue;
        dep[v]=dep[x]+1;dfs(v,x);
        s[x]+=s[v];
    }
}
void dp(int x,int fa){
    if(x!=1)pr[x]=pr[fa]-s[x]-s[x]+s[1];
    for(int i=head[x];i;i=e[i].net){
        int v=e[i].to;
        if(v==fa)continue;
        dp(v,x);
    }
}
void workb(){
    for(int i=1;i<=n;++i)s[i]=0;
    dep[1]=0;dfs(1,1);
    for(int i=1;i<=n;++i)pr[i]=0;
    for(int i=1;i<=n;++i)pr[1]+=dep[i]*re[i];
    dp(1,1);
}

signed main(){
    int T;scanf("%lld",&T);
    for(int ask=1;ask<=T;++ask){
        scanf("%lld",&n);
        for(int i=1;i<=n;++i)head[i]=0;tot=0;
        for(int i=1;i<n;++i){
            int u,v;scanf("%lld%lld",&u,&v);
            add(u,v);add(v,u);
        }
        int type;scanf("%lld",&type);
        for(int i=1;i<=n;++i)scanf("%lld",&re[i]);  
        if(type)worka();
        else workb();
        for(int i=1;i<=n;++i)printf("%lld ",pr[i]);printf("\n");
    }    
    return 0;
}

标签:const,NOIP,int,sum,fa,赛加,maxn,include,模拟
来源: https://www.cnblogs.com/Chencgy/p/16313022.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有