2022“杭电杯”中国大学生算法设计超级联赛(10)题解报告

Problem G Even Tree Split

题解:

对每条边,如果删去该边后两棵树点数都为奇数,则称其为好边。显见一个边集是合法的当且仅当边集内都为好边。则答案为2的c次方,其中c为好边数量。

代码:

#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<string>
#include<cstring>
#include<cmath>
#include<set>
#include<map>
#include<stack>
#define int long long
#define double long double
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;

const int N = 1e6 + 10;
const int mod = 998244353;

int n, ans, cnt[N];
vector<int> e[N];

int qpow(int x, int y){
    int res = 1;
    while(y){
        if(y & 1) res = res * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return res;
}

void dfs(int u, int fa){
    cnt[u] = 1;
    for(auto v : e[u]){
        if(v == fa) continue;
        dfs(v, u);
        cnt[u] += cnt[v];
    }
    if(u != 1 && cnt[u] % 2 == 0) ans++;
}

void solve()
{
    cin >> n;
    for(int i = 1; i <= n; i ++){
        cnt[i] = 0;
        e[i].clear();
    }
    ans = 0;
    for(int i = 1, u, v; i < n; i++){
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs(1, 0);
    cout << qpow(2, ans) - 1 << '\n';
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int t = 1;
    cin >> t;
    while(t--){
        solve();
    }
}

Problem I Painting Game

题解:

打表找到规律即可。

代码:

#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<string>
#include<cstring>
#include<cmath>
#include<set>
#include<map>
#include<stack>
#define int long long
#define double long double
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;

int n, m, a[110], b[110];
string s;

void solve()
{
    cin >> n >> s;
    a[1] = 1;
    a[1] = 1;
    a[2] = 1;
    a[3] = 1;
    a[4] = 2;
    a[5] = 2;
    a[6] = 3;
    a[0] = 0;
    b[1] = 1;
    b[2] = 1;
    b[3] = 2;
    b[4] = 2;
    b[5] = 3;
    b[6] = 3;
    b[0] = 0;
    if(s[0] == 'A') cout << n / 7 * 3 + a[n % 7] << '\n';
    else cout << n / 7 * 3 + b[n % 7] << '\n';
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int t = 1;
    cin >> t;
    while(t--){
        solve();
    }
}

Problem C Wavy Trees

题解:

必定是一大一小交替,做两次取min即可。

代码:

#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<string>
#include<cstring>
#include<cmath>
#include<set>
#include<map>
#include<stack>
#define int long long
#define double long double
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;

const int N = 1e6 + 10;

int n, a[N], b[N];
string s;

void solve()
{
    cin >> n;
    for(int i = 1; i <= n; i ++) cin >> a[i];
    int ans1 = 0, ans2 = 0;;
    for(int i = 2; i <= n; i++){
        b[i] = a[i] - a[i - 1];
    }
    for(int i = 2; i <= n; i++){
        if(i % 2 == 0){
            if(b[i] >= 0){
                ans1 += b[i] + 1;
                b[i + 1] += b[i] + 1;
            }
        }
        else{
            if(b[i] <= 0){
                ans1 -= b[i] - 1;
                b[i + 1] += b[i] - 1;
            }
        }
    } 
    for(int i = 2; i <= n; i++){
        b[i] = a[i] - a[i - 1];
    }
    for(int i = 2; i <= n; i++){
        if(i % 2){
            if(b[i] >= 0){
                ans2 += b[i] + 1;
                b[i + 1] += b[i] + 1;
            }
        }
        else{
            if(b[i] <= 0){
                ans2 -= b[i] - 1;
                b[i + 1] += b[i] - 1;
            }
        }
    } 
    cout << min(ans1, ans2) << '\n';
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int t = 1;
    cin >> t;
    while(t--){
        solve();
    }
}

Problem A Winner Prediction

题解:

先让1号选手赢下所有和他有关的比赛,设此时选手i赢了ai场比赛。如果存在某个ai > a1则1号
选手不可能成为冠军。否则选手i至多还能再赢bi = a1 - ai场比赛。考虑建立一张网络流图:每场未
进行的比赛在图中用一个点表示,源点向它连容量为1的边,它向它的两个参赛选手的对应点各自连容量为1的边;选手i的对应点向汇点连容量为bi的边。计算该图最大流,若源点出发的边满流则答案为 YES ,否则为 NO 。

代码:

#include<iostream>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<string>
#include<map>
#include<set>
#include<queue>
using namespace std;
#define debug(x) cout<<#x<<": "<<(x)<<endl;
#define debug2(x,y) cout<<#x<<":"<<endl;for(int i=1;i<=y;++i)cout<<x[i]<<" ";cout<<endl;
#define mem(x,y) memset(x,y,sizeof(x));
#define int long long
#define double long double
const int inf=0x3f3f3f3f3f3f3f3f;
const double eps=1e-9;
const double PI=acos(-1.0);
const int maxn=1e6+10;

struct Edge
{
    int fr,to,cap,flow;
    Edge(int f,int t,int c,int ff):fr(f),to(t),cap(c),flow(ff){}
};

int n,m1,m2;
int s,t;
vector<int> edg[maxn];
vector<Edge> net;
int dep[maxn];
int cur[maxn];
bool vis[maxn];
int cnt[maxn];
int dotnum[maxn];

void addedge(int fr,int to,int cap)
{
    net.push_back(Edge(fr,to,cap,0));
    net.push_back(Edge(to,fr,0,0));
    int tot=net.size();
    edg[fr].push_back(tot-2);
    edg[to].push_back(tot-1);
}

bool bfs()
{
    for(int i=0;i<=n;++i)
    vis[i]=0;
    queue<int> q;
    q.push(s);
    dep[s]=1;vis[s]=1;
    while(!q.empty())
    {
        int p=q.front();
        q.pop();
        for(int i:edg[p])
        {
            if(vis[net[i].to]||net[i].flow>=net[i].cap)continue;
            vis[net[i].to]=1;
            q.push(net[i].to);
            dep[net[i].to]=dep[p]+1;
        }
    }
    return vis[t];
}

int dfs(int fr,int x)
{
    if(fr==t||x==0)return x;
    int res=0;
    for(int &i=cur[fr];i<(int)edg[fr].size();++i)
    {
        Edge &it=net[edg[fr][i]];
        if(dep[it.to]==dep[fr]+1)
        {
            int t=dfs(it.to,min(x,it.cap-it.flow));
            it.flow+=t;
            net[edg[fr][i]^1].flow-=t;
            res+=t;
            x-=t;
            if(x<=0)break;
        }
    }
    if(res==0)dep[fr]=0;
    return res;
}

int dinic()
{
    int res=0;
    while(bfs())
    {
        for(int i=0;i<=n;++i)
        cur[i]=0;
        res+=dfs(s,inf);
    }
    return res;
}

void work()
{
    int tot=0;s=++tot;t=++tot;
    cin>>n>>m1>>m2;
    net.clear();
    for(int i=1;i<=n;++i)
    cnt[i]=dotnum[i]=0;
    for(int i=1;i<=n+m2+2;++i)
    edg[i].clear();
    int fr,to,flg;
    for(int i=1;i<=m1;++i)
    {
        cin>>fr>>to>>flg;
        if(flg==1)++cnt[fr];
        else ++cnt[to];
    }
    int ans=0;
    for(int i=1;i<=m2;++i)
    {
        cin>>fr>>to;
        if(fr==1||to==1)++cnt[1];
        else
        {
            if(dotnum[fr]==0)dotnum[fr]=++tot;
            if(dotnum[to]==0)dotnum[to]=++tot;
            addedge(s,++tot,1);
            addedge(tot,dotnum[fr],1);
            addedge(tot,dotnum[to],1);
            ++ans;
        }
    }
    if(n==1)
    {
        cout<<"YES\n";
        return;
    }
    for(int i=2;i<=n;++i)
    {
        if(cnt[i]>cnt[1])
        {
            cout<<"NO\n";
            return;
        }
        if(dotnum[i])
        addedge(dotnum[i],t,cnt[1]-cnt[i]);
    }
    n=tot;
    if(dinic()==ans)cout<<"YES\n";
    else cout<<"NO\n";
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // cout<<fixed<<setprecision(6);
    int _=1;
    cin>>_;
    while(_--)
    work();
    return 0;
}

Problem D Average Replacement

题解:

记deg(i)表示i的朋友数量,则每个连通块内\sum a_{i}(deg(i) + 1)为一定值。

代码:

#include<iostream>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<string>
#include<map>
#include<set>
#include<queue>
using namespace std;
#define debug(x) cout<<#x<<": "<<(x)<<endl;
#define debug2(x,y) cout<<#x<<":"<<endl;for(int i=1;i<=y;++i)cout<<x[i]<<" ";cout<<endl;
#define mem(x,y) memset(x,y,sizeof(x));
#define int long long
// #define double long double
const int inf=0x3f3f3f3f3f3f3f3f;
const double eps=1e-9;
const double PI=acos(-1.0);
const int maxn=1e6+10;

int n,m;
int a[maxn];
vector<int> edg[maxn];
int d[maxn];
double ans[maxn];
int fa[maxn],num[maxn],sum[maxn];

    void init()
    {
        for(int i=1;i<=n;++i)
        {
            fa[i]=i;
            num[i]=1;
            sum[i]=0;
        }
    }
    int find(int x)
    {
        if(fa[x]!=x)return fa[x]=find(fa[x]);
        return fa[x];
    }
    void merge(int x,int y)
    {
        x=find(x);y=find(y);
        if(x==y)return;
        if(num[x]<num[y])swap(x,y);
        fa[y]=x;
        num[x]+=num[y];
        sum[x]+=sum[y];
    }

void work()
{
    scanf("%lld %lld",&n,&m);
    for(int i=1;i<=n;++i)
    {
        edg[i].clear();
        d[i]=0;
    }
    init();
    for(int i=1;i<=n;++i)
    scanf("%lld",&a[i]);
    int fr,to;
    for(int i=1;i<=m;++i)
    {
        scanf("%lld %lld",&fr,&to);
        edg[fr].push_back(to);
        edg[to].push_back(fr);
        ++d[fr];++d[to];
    }
    for(int i=1;i<=n;++i)
    sum[i]=d[i]+1;
    for(int fr=1;fr<=n;++fr)
    {
        for(int to:edg[fr])
        {
            merge(fr,to);
        }
    }
    for(int i=1;i<=n;++i)
    ans[i]=0;
    for(int i=1;i<=n;++i)
    {
        int fa=find(i);
        ans[fa]+=1.0*(d[i]+1)*a[i];
    }
    for(int i=1;i<=n;++i)
    {
        int fa=find(i);
        if(fa!=i)continue;
        ans[i]=ans[i]/sum[i];
    }
    for(int i=1;i<=n;++i)
    {
        int fa=find(i);
        // cout<<ans[fa]<<'\n';
        printf("%.6lf\n",ans[fa]);
    }
}

signed main()
{
    // ios::sync_with_stdio(0);
    // cin.tie(0);cout.tie(0);
    // cout<<fixed<<setprecision(6);
    int _=1;
    scanf("%lld",&_);
    while(_--)
    work();
    return 0;
}

Problem B Photos

代码:

#include<cstdio>
#include<vector>
#include<algorithm>

using namespace std;

vector<pair<int,int> > S,T;vector<int> V;

int sumlen[200000];

int query_pos(int x)
{
    int pos=lower_bound(T.begin(),T.end(),make_pair(x+1,-1))-T.begin();
    if(pos==0)return x;
    if(T[pos-1].second>=x)return -1;
    return x-sumlen[pos-1];
}

const long long MOD=998244353;
int add(int x,int y){return x+y>=MOD?x+y-MOD:x+y;}
int sub(int x,int y){return x>=y?x-y:x+MOD-y;}
struct mat
{
    long long num[2][2];
    long long *operator[](int x){return num[x];}
    mat(){for(int i=0;i<2;i++)for(int j=0;j<2;j++)num[i][j]=0;}
};
mat operator*(mat A,mat B)
{
    mat C;
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<2;j++)
        {
            for(int k=0;k<2;k++)C[i][j]=add(C[i][j],A[i][k]*B[k][j]%MOD);
        }
    }
    return C;
}

mat fast_pow(mat A,int p)
{
    mat D;D[0][0]=D[1][1]=1;
    while(p)
    {
        if(p&1)D=D*A;A=A*A;p>>=1;
    }
    return D;
}

int main()
{
    //freopen("1002.in","r",stdin);
    //freopen("1002.out","w",stdout);
    int TT=0;scanf("%d",&TT);
    mat A,B;
    A[0][0]=1,A[1][0]=1,A[0][1]=1,A[1][1]=2;
    B[0][0]=0,B[1][0]=1,B[0][1]=0,B[1][1]=2;
    while(TT--)
    {
        int n=0,m=0;scanf("%d%d",&n,&m);
        for(int i=1,x=0,y=0;i<=m;i++)
        {
            scanf("%d%d",&x,&y);if(x>y)swap(x,y);
            //if(x==1)puts("??");
            if(x<y){S.push_back(make_pair(x,y-1));}
            V.push_back(y); 
        }
        sort(S.begin(),S.end());
        for(int i=0;i<S.size();i++)
        {
            if(T.empty()||T.back().second+1<S[i].first)T.push_back(S[i]);
            else T.back().second=max(T.back().second,S[i].second);
        }
        for(int i=0;i<T.size();i++)
        {
            sumlen[i]=T[i].second-T[i].first+1;if(i)sumlen[i]+=sumlen[i-1];
        }
        
        
        sort(V.begin(),V.end());V.erase(unique(V.begin(),V.end()),V.end());
        int lst=0;mat ans;ans[0][0]=ans[1][1]=1;
        for(int i=0;i<V.size();i++)
        {
            int cur=query_pos(V[i]);if(cur==-1)continue;
            ans=ans*fast_pow(A,cur-lst-1);
            ans=ans*B;
            lst=cur;
        }
        ans=ans*fast_pow(A,query_pos(n)-lst);
        printf("%lld\n",add(ans[0][0],ans[1][0]));
        
        S.clear(),T.clear(),V.clear();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值