【DP】TEST20170513

10 篇文章 0 订阅

祖先们都在看着你(ancestors.pas/c/cpp Time Limit:1s Memory Limit:256MB)

问题描述

    公元前 2000 年。在某块草原中,生活着一群牛,它们都有着自己的图腾和信仰。因此,不同信仰的牛们很自然地分为了各个部族。为了自己所在部族的神灵,牛们经常会发起圣战,
为神灵夺取地盘。在很长一段时间内,各个部族的矛盾几乎到达了不可调和的地步!这时,在众牛中,出现了一位豪杰,他在短时间内将各部族拉入麾下,建立起了血蹄部族。他就是后来为牛们所传颂的伟人:孛儿只斤•彰异牛,又名蜃牛•血蹄。他给牛们带来了文明。教会了牛们只用两个后蹄走路,空出前蹄来工作,以致于出现了后来谦逊而不失高贵,致力于侍奉自然的牛头人族。而那片草原正是后来的莫高雷。
(求不吐槽……)
    牛头人们的生活不是和平的,它们侍奉自然,对破坏自然平衡、亵渎大地母亲的行为深恶痛绝,所以,它们有着自己训练有素的军队。孛儿只斤•彰异牛逝世多年后,由于牛头人们的信仰,它们一直相信祖先彰异牛在看着它们(囧),正因为如此,它们在军队训练过程中没有丝毫懈怠。
    某天,在彰异牛的注视下,N 个牛头人(依次标号 1 到 N)加入了军队,由某牛头人队长带领。而军队审查了他们的资料后,给出了 M 条指示,第 i 条指示的内容是:第 Ai 号牛头人必须站在第 Bi 号牛头人的左边,指示之间不会出现矛盾。牛头人队长拿到指示后,便开始规划 N 个牛头人的列队方式了。
    现在,你需要用计算机的力量秒杀(1s 运行时间搞定)牛头人队长!

输入

    第一行 2 个数字 N,M。
    接下来 M 行,每行两个数字 A i 、B i 。

输出

    输出 N 行,即 N 个牛头人的站队序列。如果有多个站队序列满足要求,输出任意一个
即可。

输入样例

5 4
1 2
2 3
3 4
4 5

输出样例

1
2
3
4
5

样例解释

    1 在 2 前,2 在 3 前,3 在 4 前,4 在 5 前、只有排列 12345 满足要求。

数据范围

10%的数据 1≤N≤8、1≤M≤28。
40%的数据 1≤N≤1000、1≤M≤10 5 。
100%的数据 1≤N≤ 105 、1≤M≤ 106

分析

    拓扑排序+队列

代码

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int sm = 1e5+5;

int n,m,a,b,s;
int rd[sm],h[sm],ex[sm*10*2],fl[sm];

struct edge {
    int to,nxt;
}e[sm*10*2];

queue<int >q;

void add(int x,int y) {
    e[++s].to=y;
    e[s].nxt=h[x];
    h[x]=s;
}

int main() {

    freopen("ancestors.in","r",stdin);
    freopen("ancestors.out","w",stdout);

    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i) {
        scanf("%d%d",&a,&b);
        add(a,b);rd[b]++;
    }
    for(int i=1;i<=n;++i)
        if(!rd[i]){ 
            printf("%d\n",i);
            q.push(i);
        }
    while(!q.empty()) {
        int t=q.front();
        q.pop();
        for(int i=h[t];i;i=e[i].nxt) {
            if(!ex[i]) {
                ex[i]=1;
                rd[e[i].to]--;
                if(!fl[e[i].to]&&!rd[e[i].to]){
                    fl[e[i].to]=1;
                    printf("%d\n",e[i].to);
                    q.push(e[i].to);
                }
            }
        }
    }
    return 0;
}

愿大地母亲保佑你(bless.pas/c/cpp Time Limit:1s Memory Limit:256MB)

问题描述

    牛头人们的生活从来不是和平的。刺背野猪人、鹰身人等种族经常来骚扰他们,还有一个很欠抽的某巨魔及其麾下的军队。
    某天,仍然是在彰异牛的注视下,某牛头人临危受命,在大地母亲的保佑下,拿回了一张图纸,图纸上画的是某巨魔的组织关系示意图。这个图中包含的是某巨魔组织的从属关系
(直属上级和直属下级),图绘制出来后的形态是 N 个点的树,但是这张图没有告诉牛头人对于一对有从属关系的巨魔,谁是上级谁是下级。巨魔中肯定有个最高指挥官(即没有从属上级的巨魔),但是牛头人现在不好判断哪个巨魔是最高指挥官了。
    经过一个牛头人大德鲁伊分析后,得出结论,如果将某个巨魔从这个关系图中去掉后,这个图剩下的连通块中,点数最多那个块在所有去掉的方案中的点数最少,那么这个巨魔可能就是最高指挥官。现在,牛头人需要你找出一个最高指挥官。

输入

    第一行 1 个数字 N。
    接下来 N-1 行,每行两个数字 A i 、B i ,表示 A i 号巨魔和 B i 号巨魔之间有从属关系。

输出

    输出一个数字,即巨魔最高指挥官的编号。如果有多个输出编号最小的那个。

输入样例

3
1 2
2 3

输出样例

2

样例解释

    1 在图中去掉后,剩下的连通块点数最多的为 2 个。2 在图中去掉后,剩下的连通块点数最多的为 1 个,3 在图中去掉后,剩下的连通块点数最多为 2 个。

数据范围

20%的数据 1≤N≤1000。
100%的数据 1≤N≤ 106

分析

    f[i]表示以i为根节点的子节点个数(深搜),g[i]表示删除点i后最大联通块的最小点数,g[i]=max(f[v],n-f[i]),v表示i的子节点

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int sm = 1e6+5;

int n,s,a,b,ans,sum=0x3f3f3f3f;
int f[sm],g[sm],h[sm];
int flag;
char ch;

struct edge {
    int to,nxt;
}e[sm*2];

void read(int &x) {
    x=0;
    ch=getchar();
    flag=1;
    while(ch>'9'||ch<'0') {
        if(ch=='-')flag=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9') {
        x=x*10+ch-'0';
        ch=getchar();
    }
    x=x*flag;
}

void add(int f,int t) {
    e[++s].to=t;
    e[s].nxt=h[f];
    h[f]=s;
}

void dfs(int now,int l) {
    f[now]=1;
    for(int i=h[now];i;i=e[i].nxt) {
        if(e[i].to!=l) {
            dfs(e[i].to,now);
            f[now]+=f[e[i].to]; 
            g[now]=max(g[now],f[e[i].to]);      
        }
    }
    g[now]=max(g[now],n-f[now]);
    if(g[now]<sum||(g[now]==sum&&now<ans)) {
        sum=g[now];
        ans=now;
    }
}

int main() {
    freopen("bless.in","r",stdin);
    freopen("bless.out","w",stdout);
    read(n);
    for(int i=1;i<n;++i) {
        read(a);
        read(b);
        add(a,b);add(b,a);
    }
    dfs(1,-1);
    printf("%d\n",ans);
    return 0;
}

大地母亲在忽悠着你(cheat.pas/c/cpp Time Limit:1s Memory Limit:256MB)

问题描述

    大地母亲在护佑着你……
    ……
    对不住了,我不想写背景了。
    ……
    某牛头人:愿大地母亲宽恕你的罪行……
    ……
    如何得到宽恕?
    ……
    某牛头人:计算

i=1mn mod i
的值。
    ……
    大地母亲你真在忽悠我……

输入

    第一行 2 个数字 M、N。

输出

    输出一个数字,即答案。

输入样例

5 3

输出样例

7

样例解释

3 mod 1=0
3 mod 2=1
3 mod 3=0
3 mod 4=3
3 mod 5=3
答案为 1+3+3=7。

数据范围

20%的数据 1≤N,M≤ 106
100%的数据 1≤N,M≤ 109

分析

    商相等的模数构成等差数列(可通过打表找规律)

代码

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

typedef long long LL;

LL n,m,l,r,k,d,u,v,ans;

int main () {
    freopen("cheat.in","r",stdin);
    freopen("cheat.out","w",stdout);
    scanf("%lld%lld",&m,&n);
    if(m>n)ans=(m-n)*n,m=n;
    for(LL i=1;i<=m;i=r+1) {
        l=i;r=n/(n/i);
        ans+=(n%l+n%r)*(r-l+1)>>1;
        if(r>m)ans-=((n%(m+1)+n%r)*(r-m))>>1;
    }
    printf("%lld\n",ans);
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值