2024CSP-J模拟赛五补题报告————S12678

一,分数报告

牛奶(milk)100分
树组(Traary)100分
智乃的兔子(usagi)15分

一颗成熟的奥术飞弹(missiles)

5分
总分220分

二,赛中概括

第一题10min做完,第二,三题各调了一个小时,第四题5min输了一个大样例。

三,题目报告

牛奶(milk)

题目描述

每天一杯奶,健壮切题人。

Meowowco 有每天喝牛奶的习惯,因为牛奶是膳食中蛋白质、钙、磷、维生素 A、维生素 D 和维生素 B2 的重要来源之一,可以让经常出勤的 Meowowco 变得健壮。因此她每个月都会去买一些牛奶屯在冰箱里。

今天又到了采购的日子,Meowowco 又来到了熟悉的超市,看着冰箱里陈列着价格不同的牛奶,她摸了摸自己的钱包,

“糟糕,出勤花了太多的钱了。。。。。。”

不过这都不是问题,毕竟又不是把所有钱都花完了,只是预算被压缩了。现在问题来了,冰箱里有 n个种类的牛奶,它们有各自的数量 ai​​ 和价格 bi。作为一只学过动态规划的猫,Meowowco 一个月需要 m 盒牛奶,她想知道屯够一个月的牛奶量的最小开销。

输入描述

第一行二个整数 n,m,表示牛奶的种类和牛奶需求量。

接下来 nn 行,每行两个整数 ai,bi,表示第 i 种牛奶的数量(盒),和这种牛奶的单价(元)。

保证超市里牛奶的数量大于等于 Meowowco 的需求,即保证 ∑ai≥m。

输出描述

包含一个整数,表示 Meowowco 采购所需的牛奶所要的最小费用。

输入样例

5100
205
409
103
808
306
输出样例
630
样例解释

10×3+20×5+30×6+40×8=30+100+180+320=630,即售价为 3、5、6 的牛奶全部购入,售价为 8 的牛奶购入 40 盒。

数据范围

对于 50%的数据:1≤n≤10^3(1000),1≤m≤10^3(1000)
对于另外 50%的数据:1≤n≤10^5(100000),1≤m≤10^5(100000)
对于所有的数据一定满足:1≤ai≤100,1≤bi≤10^5(100000)

 第一眼多重背包,第二眼部分背包,第三眼直接做完。

AC代码

#include<bits/stdc++.h>
using namespace std;
struct A{
    
    int a,b;
}a[100005];
bool cmp(A x,A y){
    return x.b<y.b;
}
int main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i].a>>a[i].b;
    }
    sort(a+1,a+1+n,cmp);//快排
    int cnt=0,ans=m;
    for(int i=1;i<=n;i++){
        if(ans>=a[i].a){
            ans-=a[i].a;
            cnt+=a[i].a*a[i].b;//分开求和
        }else{
            cnt+=a[i].b*ans;
            break;
        }
    }
    cout<<cnt;
    return 0;
}

 

树组(Traary)

题目描述

树组(Traary)是有序的树序列。

树组把树按有序的形式组织起来的一种形式。

这些有序排列的树的集合称为树组。

。。。。。。

Meowowco 有 n 棵树苗,今天要在数组的每一个位置种(物理)上一棵树。种好之后,我们称它为树组。

最开始,树组中所有的树的高度为 0。每天过后,每棵树会自然生长 1 单位高度。

Meowowco 的种树过程持续 m 天,在每一天早上,她有三种操作:

op=1:选择某棵树 x 对其施展魔法,该效果持续 k 天(包括当天)。拥有魔法效果的树每天晚上会额外生长 1 单位高度。若施展时该树已经存在魔法效果,则覆盖原来的魔法效果(也就是取消原来的魔法效果,加上这次的魔法效果)。

op=2:选择取消某棵树 x 的魔法效果,可能会对没有施加魔法的树进行操作。

op=3:Meowowko 想知道该天某棵树 x 的高度。

对于每个 op=3,输出一个整数 h,代表该树的高度。

输入描述

第一行输入两个整数 n,m,k。

接下来 mm 行,第 ii 行输入格式为 op,x,op∈1,2,3,1≤x≤n,代表第 i 天的操作。

输出描述

对于每个 op=3,输出一行一个整数 h,代表该树的高度。

输入样例

793
31//
31//
15//
15//
11//
31//
21//
31//
35//
输出样例
0
1
6
9
12

数据范围

对于 25%的数据:1≤n≤1000,1≤m≤1000,1≤k≤100
对于另外 25% 的数据:1≤n≤10^5(100000),1≤m≤10^5(100000),1≤k≤100
对于另外 50%数据:

1≤n≤10^5(100000),1≤m≤10^5(100000),1≤k≤10^5(100000)

 这又双叒叕是一道思维题。

上代码

#include<bits/stdc++.h>
using namespace std;
long long n,m,k,a[100005],b[100005];//a[i]表示第i棵树被用魔法长高了多大,b[i]代表第i棵树在什么时候停止用魔法
int main(){
    cin>>n>>m>>k;
    for(int i=1;i<=m;i++){
        long long op,x;
        scanf("%lld%lld",&op,&x);
        if(op==3){
            printf("%lld\n",a[x]-max(1ll*0,b[x]-i)+i-1);
        }else if(op==2){
            if(b[x]>i){
            a[x]-=(b[x]-i);
            b[x]=i;}
        }else {
            if(b[x]>i)a[x]=a[x]-b[x]+k+i,b[x]=i+k;
            else a[x]=a[x]+k,b[x]=i+k;
        }
    }
    return 0;
}

智乃的兔子(usagi)

题目描述

Chino 是一个可爱的初中生,超喜欢兔子 (和 Cocoa) …!?精通咖啡,并且能干可靠。

今天 Chino 在梦境世界中被可爱的兔子环绕,它们都是这个梦境世界的卡密——Cocoa 的使徒。每一只棉花糖般的兔子都有一个可爱值 ai​​。

“超想和可爱的小兔子们贴贴 ∼∼”

因此她向 Cocoa 许愿:请让我挑选出一些可爱的兔子。

但是,Cocoa 并不希望 Chino 随意挑选兔子,她希望 Chino 挑选出的兔子的可爱值的和是 7 的倍数。Cocoa 作为这个世界的卡密,觉得仅有这一条挑选规则会让游戏变得很无趣,她制定规则的目的,很可能是,吃掉 Chino…!?于是她又增加了一条规则:

Cocoa 亲吻了所有的兔子,它们都受到了”祝福”,当 Chino 选择这只兔子之后,她将会获得祝福值 bib​i​​。当 Chino 拥有的祝福值超过 H 点时,会被 Cocoa 吃掉。

Chino 想知道怎么样才能完成挑选可爱值和为 7 的倍数的兔子,可爱和最大的同时还不会被吃掉。

输入描述

第一行包含两个正整数 n 和 H。

第二行包含 n 个非负整数 a​i​​,表示每只兔子的可爱值。

第二行包含 n 个非负整数 b​i​​,表示每只兔子的祝福值。

输出描述

输出单行,包含一个整数 S,表示挑选可爱值和为 7 的倍数的兔子,且不会被吃掉的最大可爱值和。

输入样例1

1010////////////////
9373644599
0111100100
输出样例1
56

输入样例2

310//
434
655

输出样例2

7
数据范围
对于测试点 1∼51≤n≤20,H=20
对于测试点 6~101≤n≤100,1≤H≤100
对于前 50%的数据1≤ai≤10^4(10000),0≤bi≤10
对于测试点 11~151≤n≤10000,H=998244353
对于测试点 16~201≤n≤10000,1≤H≤1000
对于 100%的数据1≤ai≤10^9(1000000000),0≤bi≤10

01背包改编版

赛中15分代码:

#include<bits/stdc++.h>
using namespace std;
long long a[1000005],b[1000005],dp[1000005],maxx=0;
int main(){
    int n,h;
    cin>>n>>h;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<=n;i++)cin>>b[i];
    for(int i=1;i<=n;i++){
        for(int j=h;j>=1;j--){
            dp[j]=max(dp[j],dp[j-b[i]]+a[i]);
            if(dp[j]%7==0)maxx=max(maxx,dp[j]);
        }
    }
    cout<<maxx;
    return 0;
}

AC代码: 

#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
/*可爱值=价值,祝福值=重量
n件物品在容量h下的最大价值,且价值和为7的倍数
由于每件物品只能选择1次,因此可以
转换为01背包,并且多一维限制
dp[i][j][k]:容量j下选第i件物品得到%7余数为k的最大价值和
*/
const int N=1e5;
ll n,m,w[N],v[N],ans;
int main () {
	cin>>n>>m;  //h==重量m
	for(int i=1; i<=n; i++)   cin>>v[i];
	for(int i=1; i<=n; i++)   cin>>w[i]; //祝福值=重量
	if(m==998244353) { //特殊容量,开数组放不下,
		//但因为祝福值(重量)<=10可理解为背包容量无限
		//因此dp[i][j][k]可以退化为dp[i][k]
		ll dp[N][10]= {0};
		for(int i=1; i<7; i++)	dp[0][i]=-1e18;
		//除dp[0][0]外,dp[0][其余]不存在
		for(int i=1; i<=n; i++) {
			for(int k=0; k<7; k++) {
				dp[i][k]=max(dp[i-1][k],dp[i-1][((k-v[i])%7+7)%7]+v[i]);
				//((1-100)%7+7)%7 = (-99%7+7)%7=(-1+7)%7=6
				//((6-1)%7+7)%7 =(5%7+7)%7 =12%7=5
				//不放i,和放i前的最大价值和+v[i]
			}
		}
		cout<<dp[n][0];	//余数为0
		return 0;
	}
	ll dp[2][1005][10]= {0};
	memset(dp,-0x3f3f,sizeof dp);
	dp[0][0][0]=0;
	for(int i=1; i<=n; i++) {
		for(int j=0; j<=m; j++) {
			for(int k=0; k<7; k++) {
				if(j>=w[i])
					dp[i&1][j][k]=max(dp[!(i&1)][j][k],dp[!(i&1)][j-w[i]][((k-v[i])%7+7)%7]+v[i]);
				else dp[i&1][j][k]=dp[!(i&1)][j][k];
			}
		}
	}
	for(int i=0; i<=m; i++) ans=max(ans,dp[n&1][i][0]);
	cout<<ans;
	return 0;
}

一颗成熟的奥术飞弹(missiles) 

 

奥术飞弹是一个非指向性的技能,在施法前可以指定弹道,并对路径上第一个碰撞的目标造成伤害。

作为一颗成熟的奥术飞弹,你应该学会自己决定用于攻击目标的最短路径,并且 100% 命中目标。

题目描述

Meowowco 正在玩一款未知的 1V1 游戏,游戏创建后会随机创建一个有 n 个房间的地图,由 m条通道相连,房间与房间之间最多只有一个通道,直接由通道相连的房间的距离可以记为 1,整张地图所有房间两两可达。

Meowowco 出生在编号为 1 的房间,而她的对手出生在编号为 n 的房间。现在 Meowowco 需要创造军队或者释放技能去击败对手,不过今天她有着更高级的黑魔法加持(指自瞄),令”奥术飞弹”变成”成熟的奥术飞弹”,只释放”奥术飞弹”就可以获得胜利。

作为一颗成熟的奥术飞弹,不管当前处于哪个房间,都会瞬间规划好 一条 前往目标所在位置的最短飞行弹道(当然,最短飞行弹道有时候并不是唯一的,所以有多条最短飞行弹道时会随机选择一条),如果它没有沿着当前房间规划好的最短飞行弹道飞行,记为偏离轨迹 11 次。

作为一颗成熟的奥术飞弹,应该会自己计算一条有着“大可能性“的飞行弹道。由于有些房间的最短飞行弹道不唯一,飞行弹道可能偏离也可能不偏离,”大可能性”飞行弹道要求 可能产生的偏离数尽可能大

一个房间如果有多条通往目标的最短飞行弹道,则可能偏离数增加 11,目标是找到有最多这样房间的飞行弹道。

下面将举个栗子来解释它:

对这个地图来说:

image-20240918174721172

6 \                                                   

  \  \

    \  \

      4 5

     /    \ \

   /        \/

2         3

  \       /

    \    /

      1

它有 3 条从 1 到 6 的最短飞行弹道:

  • 1 => 2 => 4 => 6
  • 1 => 3 => 4 => 6
  • 1 => 3 => 5 => 6

假如你现在处于房间 1,那么你可以选择房间 2 和房间 3 ,因为 2 和 3 都在最短飞行弹道上,所以不管前往哪个房间都会让可能偏离数增加,此时可能偏离数为 1;

当飞弹选择 1=>2 时,接下来它只能沿着 2 => 4 => 6,飞行,因此这条弹道的可能偏离数为 1。

当飞弹选择 1 => 3 时,接下来的房间 4 和 5 都处于最短飞行弹道上,不管前往哪个房间都会让可能偏离数增加,此时可能偏离数增加到 2;之后都只有一条弹道到达 6,因此这两条弹道的可能偏离数为 2。

综上所述,

  • 1 => 2 => 4 => 6 的可能偏离数为 1。
  • 1 => 3 => 4 => 6 的可能偏离数为 2。
  • 1 => 3 => 5 => 6 的可能偏离数为 2。

最大的可能偏离数为 2。

寻找出所有的最短飞行弹道,每条最短飞行弹道都有一个可能偏离数,找到其中最大的可能偏离数,输出最短飞行弹道条数和最大的可能偏离数。


简而言之,就是 n 个点的无向连通图,无重边和自环,目标是从 1 点到达 n 点。在一个点上,如果有多条最短路径到达终点,则 可能偏离数 加一,求出最短路径的总条数,以及所有最短路中可能偏离数的最大值。

输入描述

第一行输入两个正整数 n 和 m,表示房间个数和通道个数。

接下来 m 行,每行包含两个正整数 u,v,表示房间 u 到房间 v 存在一条通道。

输出描述

输出最短飞行弹道条数和最大的可能偏离数,由于最短飞行弹道的条数可能很大,请对 998244353 取模。

输入样例1

67
12
34
24
13
35
46
56
输出样例1
32
输入样例2
78
12
13
34
24
45
46
57
67
输出样例2
42
数据范围
对于测试点 1∼51≤n≤10
对于测试点 6∼101≤n≤50
对于测试点 11∼151≤n≤1000
对于测试点 16∼201≤n≤100000
对于 100%的数据n−1≤m≤2×n,保证图连通。

AC代码

#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
/*可爱值=价值,祝福值=重量
n件物品在容量h下的最大价值,且价值和为7的倍数
由于每件物品只能选择1次,因此可以
转换为01背包,并且多一维限制
dp[i][j][k]:容量j下选第i件物品得到%7余数为k的最大价值和
*/
const int N=1e5;
ll n,m,w[N],v[N],ans;
int main () {
	cin>>n>>m;  //h==重量m
	for(int i=1; i<=n; i++)   cin>>v[i];
	for(int i=1; i<=n; i++)   cin>>w[i]; //祝福值=重量
	if(m==998244353) { //特殊容量,开数组放不下,
		//但因为祝福值(重量)<=10可理解为背包容量无限
		//因此dp[i][j][k]可以退化为dp[i][k]
		ll dp[N][10]= {0};
		for(int i=1; i<7; i++)	dp[0][i]=-1e18;
		//除dp[0][0]外,dp[0][其余]不存在
		for(int i=1; i<=n; i++) {
			for(int k=0; k<7; k++) {
				dp[i][k]=max(dp[i-1][k],dp[i-1][((k-v[i])%7+7)%7]+v[i]);
				//((1-100)%7+7)%7 = (-99%7+7)%7=(-1+7)%7=6
				//((6-1)%7+7)%7 =(5%7+7)%7 =12%7=5
				//不放i,和放i前的最大价值和+v[i]
			}
		}
		cout<<dp[n][0];	//余数为0
		return 0;
	}
	ll dp[2][1005][10]= {0};
	memset(dp,-0x3f3f,sizeof dp);
	dp[0][0][0]=0;
	for(int i=1; i<=n; i++) {
		for(int j=0; j<=m; j++) {
			for(int k=0; k<7; k++) {
				if(j>=w[i])
					dp[i&1][j][k]=max(dp[!(i&1)][j][k],dp[!(i&1)][j-w[i]][((k-v[i])%7+7)%7]+v[i]);
				else dp[i&1][j][k]=dp[!(i&1)][j][k];
			}
		}
	}
	for(int i=0; i<=m; i++) ans=max(ans,dp[n&1][i][0]);
	cout<<ans;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值