CSP2019 J2参考解析

CSP2019 J2

题目传送

P5660 [CSP-J2019] 数字游戏

  • 涉及知识点:基础语法
  • 解析:直接堆1的个数进行计数即可 废话,简单题,没说的
点击查看代码
#include<bits/stdc++.h>
using namespace std;

int main(){
    int ans=0;
    string s; cin>>s;
    for(int i=0; i<s.size(); i++){
        if(s[i]=='1') ans++;
    }
    cout<<ans<<endl;
    return 0;
}

P5661 [CSP-J2019] 公交换乘

  • 涉及知识点:模拟

  • 解析:也是一个模拟题,可以直接暴力模拟

  • 如果是 subway, money+=price.

  • 如果是 bus,看有没有免费票

  • 免费票的查询可以每次从第一次行程开始,但是这样复杂度为 O(n^2)会超时。

  • 所以可以根据时间限制 45 分钟进行优化,开一个pre记录当前最早可用票的位置,这样复杂度整体可以维护在 O(n)。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e6+10;
int n,op[N],t[N],price[N],pre=1;
LL money=0;

int main(){
//    freopen("data.in", "r", stdin);
    cin>>n;
    for(int i=1; i<=n; i++) cin>>op[i]>>price[i]>>t[i];
    for(int i=1; i<=n; i++){
        if(op[i]==0){ // subway
            money += price[i];
        }else if(op[i]==1){// bus
            while(t[i]-t[pre] > 45) pre++;//时间优化
            int flag=0,p=pre;
            while(p<i){ // 找免费票
                if(op[p]==0&&t[i]-t[p]<=45&&price[i]<=price[p]){
                    t[p]=-50, flag=1; break;
                }
                p++;
            }
            if(flag==0) money+=price[i];
        }
    }
    cout<<money<<endl;
    return 0;
}

P5662 [CSP-J2019] 纪念品

  • 涉及知识点:背包问题

  • 解析:本题的数据有一定的特性,很适合拿部分分,我们将重特殊数据入手,带大家看一下,在无法想到正解情况下尽力拿分。

  • 对于 10% 的数据,T=1。

  • 试想一下,如果 T=1,意味着什么?

  • 就只有一天的交易时间,我们无论是买或不买,本质上金币的数量不可能有增长。

  • 所以这就是出题人的送分。

if(t==1) cout<<m; // 10分到手
  • 再来看下一个
  • 对于 15% 的数据,T≤100,N=1。
  • 如果 N=1,那么也就是只有一个物品的时候,这时候的买卖其实就比较简单了
  • 就拿样例1 举例
6 1 100
50 20 25 20 25 50

image

  • 我们可以将 每个递增区间看作一个买卖区间,L天买入,R天卖出,利用双指针就可以完成了。
if(n==1) {
    int l=1,r=1;
    while(r<t) {
        while(r<t && p[r+1][1]>=p[r][1]) r++;
        if(r>t) break; // l 买入,r 卖出
        m += m/p[l][1] * (p[r][1]-p[l][1]);
        l = ++r;       // 更新一个买卖阶段
    }
}
cout<<m; // 15 分到手
  • 当然这个题目的正解其实可以对问题进行转化得到
  • 买卖区间 [L,R],,L天买入,R天卖出
  • 等同于 [L,L+1] + [L+1,L+2] + [L+2,L+3] + ... +[R-1, R]。
  • 问题就可以转化为:求在第 2,3,4,...,t 天能获得的最多金币。
  • 由于每次买卖间隔不超过一天,所以需要最大化每天的金币数量
  • 这样就变成了完全背包问题,进行 (t-1)次完全背包即可。
  • 一次背包问题
  • 定义状态:f[i] 背包容量为 i时的最大价值
  • 状态转移:f[i]=max(f[i], f[j-w]+v)
  • 目标答案:f[m]
  • 其中:代价为 p[i][j],价值为每天交易的获利 p[i+1][j]-p[i][j]。
  • 另外还可以加一个优化: if(p[i+1][j] > p[i][j]) // 优化:有价值才用
for(int i=1; i<t; i++) {
    memset(f, 0, sizeof(f));
    for(int j=1; j<=n; j++) {
        if(p[i+1][j] > p[i][j]) // 优化:有价值才用
        for(int k=p[i][j]; k<=m; k++) {
            f[k] = max(f[k], f[k-p[i][j]]+p[i+1][j]-p[i][j]);
        }
    }
    m += f[m];
}
cout<<m;
  • 其实考场上写如下程序是最为保险的,因为有时候自己也不一定确定正解是否是正解。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=110, M=1e4+10,INF=0x3f3f3f3f;
int t,n,m,p[N][N],f[M];

int main() {
// freopen("data.in", "r", stdin);
    cin>>t>>n>>m;
    for(int i=1; i<=t; i++)
        for(int j=1; j<=n; j++) cin>>p[i][j];
    if(t==1) {
    //  cout<<m;
    } else if(n==1) {
        int l=1,r=1;
        while(r<t) {
            while(r<t && p[r+1][1]>=p[r][1]) r++;
            if(r>t) break; // l 买入,r 卖出
            m += m/p[l][1] * (p[r][1]-p[l][1]);
            l = ++r;       // 更新一个买卖阶段
        }
    } else { // 正解:完全背包
        for(int i=1; i<t; i++) {
            memset(f, 0, sizeof(f));
            for(int j=1; j<=n; j++) {
                if(p[i+1][j] > p[i][j]) // 优化:有价值才用
                for(int k=p[i][j]; k<=m; k++) {
                    f[k] = max(f[k], f[k-p[i][j]]+p[i+1][j]-p[i][j]);
                }
            }
            m += f[m];
        }
    }
    cout<<m<<endl;
    return 0;
}

P5663 [CSP-J2019] 加工零件

  • 涉及知识点:最短路
  • 解析:题目需要进行转化
  • 转化为:问是否存在【从 1->a 的最短路 dis[a] <= L,且二者同奇偶性】的情况。
  • 同奇偶性是指:L,L+2,L+4,L+6,... ,这样的性质。
  • 这时候其实就是求单源最短路了,可以使用 spfa-其实就是bfs,dijkstra。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+10,INF=0x3f3f3f3f;
int n,m,q,head[N],cnt=0,dis[N][2];
struct T {
    int to,nxt;
    T(int a=0,int b=0):to(a),nxt(b) {}
} G[N<<1], que[N<<1], p;

void add(int u,int v) {
    G[++cnt].to=v, G[cnt].nxt=head[u], head[u]=cnt;
}
void bfs() {
    memset(dis, 0x3f, sizeof(dis));
    int front=0, tail=-1;
    dis[1][0]=0,que[++tail] = T(1,0);
    while(front<=tail) {
        p = que[front++];
        int u=p.to, type=p.nxt, dist=dis[u][type];
        for(int i=head[u]; ~i; i=G[i].nxt) {
            int v=G[i].to;
            if(dis[v][type^1] > dist+1) {
                dis[v][type^1] = dist+1;
                que[++tail] = T(v,type^1);
            }
        }
    }
}
int main() {
//    freopen("data.in", "r", stdin);
    ios::sync_with_stdio(0);
    memset(head, -1, sizeof(head));
    cin>>n>>m>>q; int u,v,a,l;
    for(int i=1; i<=m; i++) {
        cin>>u>>v;
        add(u,v), add(v,u);
    }
    bfs();
    while(q--) {
        cin>>a>>l;
        if(head[1]==-1) puts("No");
        else if(l>=dis[a][l&1]) puts("Yes");
        else puts("No");
    }
    return 0;
}
posted @ 2022-10-02 17:46  HelloHeBin  阅读(261)  评论(0编辑  收藏  举报