2018.07.08【2018提高组】模拟C组

22 篇文章 0 订阅
21 篇文章 0 订阅

0 音乐节拍

FJ准备教他的奶牛弹奏一首歌曲,歌曲由N(1<=N<=50,000)种音节组成,编号为1到N,而且一定按照从1到N的顺序进行弹奏,第i种音节持续B_i(1<=B_i<=10,000)个节拍,节拍从0开始计数,因此从节拍0到节拍B_1-1弹奏的是第1种音节,从B_1到B_1+B_2-1弹奏的是第2种音节,依此类推。
  最近奶牛对弹琴不感兴趣了,他们感觉太枯燥了。所以为了保持奶牛们注意力集中,FJ提出Q(1<=Q<=50,000)个问题,问题的格式都是“第T次节拍弹奏的是哪种音节”
  每个问题对应一个T_i(0<=T_i<=节拍总数-1)请你帮奶牛来解决。
前缀和+二分
或排序问题离线做

#include <cstdio>
#include <algorithm>

using namespace std;

int n,q,b[50004];

int find(int k){
    int l=1,r=n,mid,ans;
    while (l<=r){
        mid=(l+r)/2;
        if (b[mid-1]<=k&&b[mid]-1>=k) ans=mid;
        if (b[mid]-1<=k) l=mid+1;
        else r=mid-1;
    }
    return ans;
}

int main(){
    freopen("mnotes.in","r",stdin);
    freopen("mnotes.out","w",stdout);
    scanf("%d%d",&n,&q);
    for (int i=1;i<=n;i++){
        scanf("%d",&b[i]);
        b[i]+=b[i-1];
    }
    for (int i=1;i<=q;i++){
        int t;
        scanf("%d",&t);
        printf("%d\n",find(t));
    }
}

1 【Usaco2009 gold 】电视游戏问题

农夫约翰的奶牛们游戏成瘾!本来FJ是想要按照陶叫兽的做法拿她们去电击戒瘾的,可是后来他发现奶牛们玩游戏之后比原先产更多的奶。很明显,这是因为满足的牛会产更多的奶。
但是,奶牛们在哪个才是最好的游戏平台这个问题上产生了巨大的分歧。一只奶牛想要买一台Xbox 360来跑《光晕3》;另外一只奶牛想要一台任天堂Wii来跑《任天堂明星大乱斗X》;第三只奶牛想要在PlayStation 3上面玩《潜龙谍影4》,顺便还能看某些高画质的日本电影。
FJ想要在给定的预算内购入一些游戏平台和一些游戏,使他的奶牛们生产最多的奶牛以养育最多的孩子。
FJ研究了N(1 <= N <= 50)种游戏平台,每一种游戏平台的价格是P_i(1 <= P_i <= 1000),并且每一种游戏平台有G_i(1 <= G_i <= 10)个只能在这种平台上运行的游戏。很明显,奶牛必须先买进一种游戏平台,才能买进在这种游戏平台上运行的游戏。每一个游戏有一个游戏的价格GP_j(1 <= GP_j 价格 <= 100)并且有一个产出值PV_j(1 <= PV_j<= 1000000),表示一只牛在玩这个游戏之后会产出多少牛奶。
最后,农夫约翰的预算为V(1 <= V <= 100000),即他最多可以花费的金钱。请帮助他确定应该买什么游戏平台和游戏,使得他能够获得的产出值的和最大。
考虑下面的数据,有N种游戏平台,并且有V=800预算。第一种游戏平台花费300并且有两个游戏,价格分别为30和25,它们的产出值如下所示:
游戏 # 花费 产出值
1 30 50
2 25 80
第二种平台价格为600,并且只有一种游戏:

游戏 # 花费 产出值
1 50 130
第三种平台价格为400,并且有三种游戏:

游戏 # 花费 产出值
1 40 70
2 30 40
3 35 60
农夫约翰应该买第1和第3种平台,并且买平台1的游戏2,还有平台3的游戏1和游戏3。使得
他最后的产出值最大,为210:

产出值
预算: 800
平台 1 -300
游戏 2 -25 80
平台 3 -400
游戏 1 -40 70
游戏 3 -35 60


总计: 0 (>= 0) 210

一眼看出是动态规划,但是不会转移······凉凉
emmm······
f[i]表示花费为i时的最大产出值
对于每个游戏平台,开一个数组ff记录上次的f[i],ff[i]=f[i-p]
然后对于该游戏平台内的游戏,ff[i]=max(ff[i-a)(有‘–’的东西都要倒着来)
然后用ff[i]更新f[i]

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>

using namespace std;

int n,k,ans;
int f[100005],f2[100005];

int main(){
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++){
        int m,p,a,g;
        scanf("%d%d",&p,&m);
        for (int l=p;l<=k;l++)
            f2[l]=f[l-p];       
        for (int j=1;j<=m;j++){
            scanf("%d%d",&a,&g);            
            for (int l=k-a;l>=p;l--){               
                f2[l+a]=max(f2[l+a],f2[l]+g);
            }
        }
        for (int l=p;l<=k;l++)
        if (f2[l]>f[l]) f[l]=f2[l];
    }

    printf("%d",f[k]);
}

2 【Usaco2009 gold 】头晕的奶牛【图论借用】(有多解,需比较)

 奶牛们发现,在农场里面赛跑是很有趣的一件事。可是她们一旦在农场里面不断地转圈,就会变得头晕目眩。众所周知,眩晕的奶牛是无法产奶的。于是,农夫约翰想要把他农场里面的双向道路全部改为单向道路,使得他的农场里面一个“圈”都没有,以避免他的奶牛们被搞得晕头转向。如果奶牛可以经过若干条道路回到起点,那么这些道路就称为一个“圈”。
  农场有N(1 <= N <= 100000)片草地,编号为1到N。这些草地由M1(1 <= M1 <= 100000)条单向道路和M2(1 <= M2 <= 100000)条双向道路连接起来。任何一条道路都不会把一片草地和这篇草地本身连接起来。但是,任意两片草地之间都可能有多条道路连接。不保证任意两片草地之间都有路径相连。
  你的任务是给所有的双向道路设定一个方向,使得整个农场(只剩下单向道路)最后一个圈都没有。也就是说,不存在一个单向道路序列的终点和起点重合。数据保证一开始就有的单向道路中,一个圈都没有。而且一开始就有的单向道路不能改变。
  单向道路的起点是草地A_i(1 <= A_i <= N),终点是草地B_i(1 <= B_i <= N)。双向道路连接草地X_i(1 <= X_i <= N)和Y_i(1 <= Y_i <= N)。
  
根据单向边拓补排序后,双向边中顺序小的点连向顺序大的点即可

#include <cstdio>

using namespace std;

const int N=1000006;
int n,m1,m2,cnt;
int ls[N],ne[N],to[N],r[N],a[N],b[N];

int main(){
    freopen("dizzy.in","r",stdin);
    freopen("dizzy.out","w",stdout);
    scanf("%d%d%d",&n,&m1,&m2);
    for (int i=1;i<=m1;i++){
        int x,y;
        scanf("%d%d",&x,&y); 
        r[y]++;
        ne[++cnt]=ls[x];ls[x]=cnt;to[cnt]=y;
    }
    cnt=0;
    for (cnt;cnt<n;cnt)
    for (int i=1;i<=n;i++)
    if (r[i]==0&&!b[i]) {
        a[i]=++cnt;b[i]=1;
        for (int t=ls[i];t;t=ne[t]){
            r[to[t]]--;
        }
    }
    for (int i=1;i<=m2;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        if (a[x]<a[y]) printf("%d %d\n",x,y);
                  else printf("%d %d\n",y,x);
    }
}

3 【Usaco2009 gold 】过路费【图论借用】

 跟所有人一样,农夫约翰以着宁教我负天下牛,休叫天下牛负我的伟大精神,日日夜夜苦思生财之道。为了发财,他设置了一系列的规章制度,使得任何一只奶牛在农场中的道路行走,都要向农夫约翰上交过路费。
  农场中由N(1 <= N <= 250)片草地(标号为1到N),并且有M(1 <= M <= 10000)条双向道路连接草地A_j和B_j(1 <= A_j <= N; 1 <= B_j <= N)。奶牛们从任意一片草地出发可以抵达任意一片的草地。FJ已经在连接A_j和B_j的双向道路上设置一个过路费L_j(1 <= L_j <= 100,000)。
  可能有多条道路连接相同的两片草地,但是不存在一条道路连接一片草地和这片草地本身。最值得庆幸的是,奶牛从任意一篇草地出发,经过一系列的路径,总是可以抵达其它的任意一片草地。
  除了贪得无厌,叫兽都不知道该说什么好。FJ竟然在每片草地上面也设置了一个过路费C_i(1 <= C_i <= 100000)。从一片草地到另外一片草地的费用,是经过的所有道路的过路费之和,加上经过的所有的草地(包括起点和终点)的过路费的最大值。
任劳任怨的牛们希望去调查一下她们应该选择那一条路径。她们要你写一个程序,接受K(1<= K <= 10,000)个问题并且输出每个询问对应的最小花费。第i个问题包含两个数字s_i和t_i(1 <= s_i <= N; 1 <= t_i <= N; s_i != t_i),表示起点和终点的草地。

因为有多个询问,因此放弃单源做多源
floyed加强版,要在计算边权同时计算点权
点权进行排序,可以保证最终得出最大点权
要将排序后的点权与原来的点对应可以采取记录每个点对应的点,这样在读入和输出调用点时可以找到要找的点的位置

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int n,m,k,q,f[260][260],a[260][260],b[260];
struct node{
    int v,o;
}c[260];

bool comp(node a,node b){
    return a.v<b.v;
} 

int main(){
    scanf("%d%d%d",&n,&m,&k);
    memset(f,0x3f,sizeof(f));
    memset(a,0x3f,sizeof(a));
    for (int i=1;i<=n;i++){
        scanf("%d",&c[i].v);
        c[i].o=i;
    }
    sort(c+1,c+1+n,comp);
    for (int i=1;i<=n;i++) b[c[i].o]=i;
    for (int i=1;i<=m;i++){
        int x,y,e;
        scanf("%d%d%d",&x,&y,&e);
        f[b[x]][b[y]]=f[b[y]][b[x]]=min(e,f[b[x]][b[y]]);
    }
    for (int t=1;t<=n;t++)
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++){
                f[i][j]=f[j][i]=min(f[i][t]+f[t][j],f[i][j]);
                a[i][j]=a[j][i]=min(a[i][j],f[i][j]+max(c[t].v,max(c[i].v,c[j].v)));
            } 
    for (int i=1;i<=k;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        printf("%d\n",a[b[x]][b[y]]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值