FYN OI 奋斗之路7~

XJOI 奋斗群 群赛 13解题报告

原题

https://cn.vjudge.net/contest/186396 (Codeforces Round #214 (Div. 2))

A - Dima and Guards

题意

输入一个数n代表花的钱数,再输入四行数据,每一行有四个数字,代表:用巧克力贿赂第一个守卫的最小代价,用果汁贿赂第一个守卫的最小代价,用巧克力贿赂第二个守卫的最小代价,用果汁贿赂第二个守卫的最小代价,输出贿赂的一种方案。

题解

水题,数据比较小,直接模拟。

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;
    scanf("%d",&n);
    int a[5],b[5],c[5],d[5];
    int cnt1[5],cnt2[5],cnt3[5],cnt4[5];
    for(int i=1;i<=4;i++){
        cin>>a[i]>>b[i]>>c[i]>>d[i];
    }
    for(int i=1;i<=4;i++){
        cnt1[i]=a[i]+c[i];
        if(cnt1[i]<=n) {
            cout<<i<<" "<<a[i]<<" "<<n-a[i];
            return 0;
        }
        cnt2[i]=a[i]+d[i];
        if(cnt2[i]<=n) {
            cout<<i<<" "<<a[i]<<" "<<n-a[i];
            return 0;
        }
        cnt3[i]=b[i]+c[i];
        if(cnt3[i]<=n) {
            cout<<i<<" "<<b[i]<<" "<<n-b[i];
            return 0;
        }
        cnt4[i]=b[i]+d[i];
        if(cnt4[i]<=n) {
            cout<<i<<" "<<b[i]<<" "<<n-b[i];
            return 0;
        }
    }
    cout<<-1;
}

B - Dima and To-do List

题意

给出n个事件和k,每个事件有一个权力值,k可以被n整除,如果取了第i个事件的权力值,那么下一个取的权力值将是第(i+k)个,问最小的权力值总和。

题解

由于k能被n整除,我们可以以i为索引处理输入的权力值的前缀(以余数判断),之后选取最小的即可,具体实现可以看代码。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=100010;
const int inf=1e9;
int a,pre[MAXN]={0};
int main(){
    int n,k,ans=0;
    int min=inf;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        scanf("%d",&a);
        if(i%k!=0){
            pre[i%k]=pre[i%k]+a;
        }
        else pre[k]=pre[k]+a;
    }
    for(int i=1;i<=k;i++){
        if(pre[i]<min){
            ans=i;
            min=pre[i];
        }
    }
    cout<<ans;
}

C - Dima and Salad

题意

有n个水果,每个水果有自己的美味值和热量,要求在使所选的水果的美味值总和除以热量等于k的条件下计算出能取的最大美味值。

题解

变形一下题中所给的公式,我们就可以得到水果价值的计算方法,假设水果美味值为a,热量为b,那么他的价值v=a-b*k。有了这个计算方法,我们将其用动态规划进行状态转移,最后的dp[n][m]就是答案。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=110;
const int inf=1e9;
struct node{
    int a;
    int b;
}f[MAXN];
int dp[MAXN][MAXN*MAXN]={0};
int n,k,b,m;
/*
bool cmp(node a,node b){
    if(a.a==b.a) return a.b<b.b;
    else return a.a<b.a;
}
*/
void init(){
    memset(dp,-10000,sizeof(dp));
    dp[0][m]=0;
}
int main(){
    scanf("%d%d",&n,&k);
    m=n*100;
    init();
    for(int i=1;i<=n;i++){
        scanf("%d",&f[i].a);
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&b);
        f[i].b=f[i].a-b*k;
        for(int j=m*2;j>=0;j--){
            dp[i][j]=max(dp[i-1][j],dp[i-1][j-f[i].b]+f[i].a);
        }
    }
    if(dp[n][m]){
        printf("%d",dp[n][m]);
    }
    else{
        printf("-1");
    }
    return 0;
}

D - Dima and Trap Graph

题意

给出一张无向图,有n个结点和m条边(有重边与环),让你取一个最大的整数x使得x对于从结点1到n所经过每一条边i,有li<=x<=ri。、

题解

用并查集实现对于每一条边的左右段点的维护,由于不知道这里怎么二分,用了快排:按照右端点大小排序,把右端点大的拍到前面,这样排序以后,1和n连通的情况就是最优解,枚举m条边不断更新答案即可。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=3010;
const int inf=1e9;
int p[MAXN];
int n,m,ans;
struct edge{
    int u,v,l,r;
}e[MAXN];
bool cmp(edge a,edge b){
    if(a.r==b.r) return a.l<b.l;
    return a.r>b.r;
}
int find(int n){
    if(p[n]==n) return n;
    else return p[n]=find(p[n]);
}
int main(){

    scanf("%d %d",&n,&m);
    for(int i=0;i<m;i++){
        scanf("%d %d %d %d",&e[i].u,&e[i].v,&e[i].l,&e[i].r);
    }
    sort(e,e+m,cmp);
    for(int i=0;i<m;i++){
        for(int j=1;j<=n;j++){
            p[j]=j;
        }
        for(int j=0;j<m;j++){
            if(e[j].l>e[i].l) continue;
            if(e[j].r<e[i].l) continue;
            p[find(e[j].u)]=find(e[j].v);
            if(find(1)==find(n)){
                ans=max(ans,e[j].r-e[i].l+1);
                break;
            }
        }
    }
    if(ans!=0){
        printf("%d",ans);
    }
    else{
        printf("Nice work, Dima!");
    }
    return 0;
}

E - Dima and Magic Guitar

题意

有i*j个音符(数字),每个音符不大于k,有s个音符代表演奏的顺序,对于演奏顺序中的两个相邻音符,他们在矩阵中的曼哈顿距离即为这两个音符的复杂度,输出最大的复杂度。

题解

由于曼哈顿距离带有绝对值,对于每一个(x,y)只有四种情况:-x-y,-x+y,x-y,x+y,并且两点之间的最大距离肯定是这四种值的某两种之差,在此基础上有暴力去不断更新最大值。由于在输入矩阵中的音符时就可以做很多处理所以并不会超时。

#include<bits/stdc++.h>
using namespace std;
const int inf=1e9;
int num[100][4];
int main() {
    int n,m,k,s,a,x,y,ans=-inf,i,j;
    scanf("%d%d%d%d",&n,&m,&k,&s);
    memset(num,1000,sizeof(num));
    for(i=1; i<=n; i++) {
        for(j=1; j<=m; j++) {
            scanf("%d",&a);
            num[a][0]=max(num[a][0],-i-j);
            num[a][1]=max(num[a][1],-i+j);
            num[a][2]=max(num[a][2],i-j);
            num[a][3]=max(num[a][3],i+j);
        }
    }
    scanf("%d",&x);
    for(i=2; i<=s; i++) {
        scanf("%d",&y);
        for(j=0; j<=3; j++) {
            ans=max(ans,num[x][j]+num[y][3-j]);
        }
        x=y;
    }
    printf("%d",ans);
}

总结

这次比赛的题目涉及的很广,动态规划、并查集、思维题都有,掌握的情况并不是很好,还要加油。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值