[APIO2008]

A.免费道路roads

题意:给定n个点m条边的图,边有黑白颜色,求是否有一个生成树满足恰好有K条黑边,并输出方案。

题解:先加白边,求出必须加的黑边,然后加黑边到K条,剩下的用白边填充。

顺便说说,边权只有01的图,生成树的权值和可以取到任意的介于[MST,MBT]的任意值,其中MST表示最小生成树,MBT最大。

我们可以发现MST和MBT的区别在与其中一些点,这些点与生成树联通的边可以选择0或者1,所以你可以把一些点的边替换,每次权值变化1,所以可以取到任意的权值.

#include<iostream>
#include<cstdio>
#include<cstring>
#define MN 20000
#define MM 100000
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < ‘0‘ || ch > ‘9‘){ if(ch == ‘-‘) f = -1;  ch = getchar();}
    while(ch >= ‘0‘ && ch <= ‘9‘){x = x * 10 + ch - ‘0‘;ch = getchar();}
    return x * f;
}

struct edge{int from,to;}e[MM+5],e2[MM+5];
int n,m,K,s[MN+5],cnt1=0,cnt2=0,q[MN+5],qx[MN+5],top,top2;

int getfa(int x){return !s[x]?x:s[x]=getfa(s[x]);}

int kruscal(edge*E,int num,int lim=MM)
{
    top=0;
    for(int i=1;i<=num&&top<lim;i++)
    {
        int x=getfa(E[i].from),y=getfa(E[i].to);
        if(x!=y)
            s[x]=y,q[++top]=i;
    }
    return top;
}

int main()
{
    n=read();m=read();K=read();
    for(int i=1;i<=m;i++)
    {
        int u=read(),v=read(),k=read();
        if(!k) e[++cnt1]=(edge){u,v};
        else  e2[++cnt2]=(edge){u,v};
    }
    int num1=kruscal(e2,cnt2),num2=kruscal(e,cnt1);
    if(num2>K||cnt1<K||num1+num2!=n-1) return 0*puts("no solution");
    memset(s,0,sizeof(s));top2=top;
    for(int i=1;i<=top;i++)
        qx[i]=q[i],s[getfa(e[q[i]].from)]=getfa(e[q[i]].to);
    if(kruscal(e,cnt1,K-num2)<K-num2) return 0*puts("no solution");
    for(int i=1;i<=top2;i++)printf("%d %d %d\n",e[qx[i]].from,e[qx[i]].to,0);
    for(int i=1;i<=top;i++)
        printf("%d %d %d\n",e[q[i]].from,e[q[i]].to,0);
    kruscal(e2,cnt2);
    for(int i=1;i<=top;i++)
        printf("%d %d %d\n",e2[q[i]].from,e2[q[i]].to,1);
    return 0;
}

B.DNA

给定一个长度为m的由ACGTN组成的字符串,定义大小关系A<C<G<T,你要把其中的N替换成ACGT的其中一个,满足最多有k个不下降的子序列的同时,求出第R大的字符串。

$m\leqslant 50000 R\leqslant 10^{12} k\leqslant 10$

题解:用f[i][j][k]表示第i到n位第i位是k,这部分分了j段的个数,这个容易转移,然后我们就一步步走呗。复杂度 O(16mk)

#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
inline ll read()
{
    ll x = 0 , f = 1; char ch = getchar();
    while(ch < ‘0‘ || ch > ‘9‘){ if(ch == ‘-‘) f = -1;  ch = getchar();}
    while(ch >= ‘0‘ && ch <= ‘9‘){x = x * 10 + ch - ‘0‘;ch = getchar();}
    return x * f;
}

ll f[50005][12][5];
int m,K,s[50005];ll R;
char st[50005];
char ch[4]={‘A‘,‘C‘,‘G‘,‘T‘};

int main()
{
    m=read();K=read();R=read();
    scanf("%s",st+1);
    for(int i=1;i<=m;i++)
    {
        if(st[i]==‘A‘) s[i]=1;
        else if(st[i]==‘C‘) s[i]=2;
        else if(st[i]==‘G‘) s[i]=3;
        else if(st[i]==‘T‘) s[i]=4;
        else s[i]=0;
    }
    if(s[m]) f[m][1][s[m]]=1;
    else f[m][1][1]=f[m][1][2]=f[m][1][3]=f[m][1][4]=1;
    for(int i=m-1;i;i--)
        for(int j=1;j<=K;j++)
            for(int k=1;k<=4;k++)
                if(!s[i]||s[i]==k)
                    for(int l=1;l<=4;l++)
                    {
                        if(k<=l) f[i][j][k]+=f[i+1][j][l];
                        else f[i][j][k]+=f[i+1][j-1][l];
                    }
    for(int i=1;i<=m;i++)
        for(int k=1;k<=4;k++)
            for(int j=1;j<=K;j++)
                f[i][j][k]+=f[i][j-1][k];
    for(int i=1,k=0;i<=m;i++)
        if(s[i])
        {
            printf("%c",st[i]);
            if(s[i]<k)--K;k=s[i];
        }
        else
        {
            for(int j=1;j<=4;j++)
                if(f[i][K-(j<k)][j]<R)
                    R-=f[i][K-(j<k)][j];
                else
                {
                    printf("%c",ch[j-1]);
                    if(j<k) --K;k=j;
                    break;
                }
        }
    return 0;
}
时间: 2024-08-04 10:09:15

[APIO2008]的相关文章

[Apio2008]免费道路[Kruscal]

3624: [Apio2008]免费道路 Time Limit: 2 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 1292  Solved: 518[Submit][Status][Discuss] Description Input Output Sample Input 5 7 2 1 3 0 4 5 1 3 2 0 5 3 1 4 3 0 1 2 1 4 2 1 Sample Output 3 2 0 4 3 0 5 3 1 1 2

bzoj 3624: [Apio2008]免费道路 生成树的构造

3624: [Apio2008]免费道路 Time Limit: 2 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 111  Solved: 49[Submit][Status] Description Input Output Sample Input 5 7 2 1 3 0 4 5 1 3 2 0 5 3 1 4 3 0 1 2 1 4 2 1 Sample Output 3 2 0 4 3 0 5 3 1 1 2 1 还是看的网上的标

【BZOJ4606】[Apio2008]DNA DP

[BZOJ4606][Apio2008]DNA Description 分析如DNA序列这样的生命科学数据是计算机的一个有趣应用.从生物学的角度上说,DNA 是一种由腺嘌呤.胞嘧啶.鸟嘌呤和胸腺嘧啶这四种核苷酸组成的链式结构.这四种核苷酸分别用大写字母A.C.G.T表示.这样,一条DNA单链可以被表示为一个只含以上四种字符的字符串.我们将这样的字符串称作一个DNA序列 .有时生物学家可能无法确定一条DNA单链中的某些核苷酸.在这种情况下,字符N将被用来表示一个不确定的核苷酸.换句话说,N可以用来

3624: [Apio2008]免费道路

3624: [Apio2008]免费道路 https://www.lydsy.com/JudgeOnline/problem.php?id=3624 题意: 一张无向图,每种边有两种类型0和1.求一个最小生成树使得有k条0边. 分析: 为了满足有k条0边的限制,先考虑0边哪些必选,如果所有1边都加入后,还有0边可以使得图不连通,那么这些0边必须选. 把必须选的加上然后再加到k,然后再加1边.中间判一下是否必选的大于k,0边是否大于等于k. 代码: 1 #include<bits/stdc++.h

[APIO2008]免费道路

# [APIO2008]免费道路 ### 第一反应 考虑朴素的克鲁斯卡尔算法加一个限制,先选鹅卵石路,且选到k个就停止 带来的问题: - ~~叶子节点特殊处理,都选上~~(但其实是连通性) - ~~而且你诡异的发现,tm,这个鹅卵石路可以突破最小生成树!!!~~(不仔细看题面的后果) ### 正解 考虑上文中的连通性,先用水泥路跑一遍$Kruskal$,然后不连通的且用到鹅卵石路的都要选上.剩下的既然水泥路可以,那么鹅卵石路也可以代替嘛,先选鹅卵石路,选到$k$个就停止 emm,那么什么时候是无

bzoj3624: [Apio2008]免费道路

具体题目:https://vjudge.net/problem/HYSBZ-3624 Description 一个王国有N个城市和M条无向道路,这M条道路中有一些是鹅卵石路一些是水泥路.现在国王要选择尽可能少的路免费,并且使每两个城市都有一条免费路径.国王打算保留刚好K条鹅卵石路.请问国王是否可以办到所有这些要求,如果能则输出路径的两个城市和路的种类,否则"no solution". HINTN <= 20000M <= 100000 Analysis如果能成功肯定是最小生

【bzoj3624】Apio2008—免费道路

http://www.lydsy.com/JudgeOnline/problem.php?id=3624 (题目链接) 题意 给出一张无向图,其中有0类边和1类边.问能否构成正好有K条0类边的生成树,并输出方案. Solution 先将所有1类边加入生成树,然后再加入0类边,那么现在加入的0类边就是必须加入的0类边,将它们打上标记.然后再将并查集初始化,继续加0类边直到数量达到K,最后加1类边. 代码 // bzoj3624 #include<algorithm> #include<io

BZOJ 3624: [Apio2008]免费道路 [生成树 并查集]

题意: 一张图0,1两种边,构造一个恰有k条0边的生成树 优先选择1边构造生成树,看看0边是否小于k 然后保留这些0边,补齐k条,再加1边一定能构成生成树 类似kruskal的证明 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=2e4+5, M=1e5+5; typedef long

【[APIO2008]免费道路】

\(kruskal\)好题 \(0\)边的数量在某些情况下是可以无限制的调控的,前提是所有必须存在的边都在生成树里了 所以应该分别求出有哪些边是必须在生成树里的,我们可以先从大到小排序,求出有哪些\(0\)边必须在生成树里,之后再从小到大排序,求出那些\(1\)边必须在生成树里 之后剩下的边就可以随便放了,调控\(0\)边的个数恰好为\(k\)即可 代码 #include<iostream> #include<algorithm> #include<cstring> #