TYZ 8/21群赛 解题报告
赛制:OI
难度:约等于NOIP
题目来自网络::
下面有详细的解说
T1
T1
窃贼和火柴
【问题描述】
一个窃贼进入了火柴仓库,想要偷尽可能多的火柴。仓库里有 m 个集装箱,
第 i 个集装箱里有 a
i 个火柴盒,每个火柴盒里有 b
i 根火柴。所有火柴盒大小相同。
窃贼的帆布背包恰能容纳 n 个火柴盒。你的任务是找出窃贼能拿走的火柴的最大
数量。他没时间重新调整火柴盒中的火柴,这就是他只是挑选不超过 n 个其包含
火柴数之和最大的火柴盒的原因。
【输入文件】
输入文件 bam.in 第一行包含整数 n(1≤n≤2·10
8
)和整数 m(1≤m≤20)。
第 i+1 行包含一对整数 a
i 和 b
i (1≤a
i≤10 8,1≤bi≤10)。所有输入的数字都是整
数。
【输出文件】
输出文件 bam.out 包含唯一一个整数代表问题的答案。
【输入样例 1】
7 3
5 10
2 5
3 6
【输出样例 1】
62
【输入样例 2】
3 3
1 3
2 2
3 1
【输出样例 2】
7
这道题目的相似型应该是一次USACO的一道题:混合牛奶1
不过不用在意这些细节啦
这个题秒懂的贪心,先排序,选取容量最大的火柴盒子先进行拿,直到背包装满为止.
代码实现方面,需要注意的是装满背包时候的减法
不过还是10多分钟就干掉了;
代码如下:
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;//这句是用来ll表示long long的数的
struct bx{
ll a,b;
};
bx r[25];
ll n,m,k;
ll ans;
int cmp(bx x,bx y)
{
return x.b>y.b;
}
int main()
{
freopen("bam.in","r",stdin);
freopen("bam.out","w",stdout);
cin>>n>>m;
for(ll i=1;i<=m;i++)
{
cin>>r[i].a>>r[i].b;
}
sort(r+1,r+1+m,cmp);
ll nw=n;
for(ll i=1;i<=m;i++)
{
if(nw>r[i].a)
{
nw-=r[i].a;
ans+=r[i].a*r[i].b;
}
else
{
ans+=nw*r[i].b;
break;
}
}
cout<
第二题’:
名字叫“第三题”(。。。。。。。。。。。。。。)
原型是POJ的2161
Lamps-O-Matic 公司装修很大的吊灯。吊灯由几层组成。(从下至上)第一层
的水晶灯直接挂在环上。把环集起来以后再挂到上一层的环上面,依此类推。最
后一层是一个挂满了灯和小环的大环(废话)。
现在由机器人来做挂灯的事。机器人身上有资源补给,挂灯的时候,它使用
一个栈来存储灯和环。一开始,这个栈是空的。机器人执行一个指令集来运作。
这个指令集是一个字符串。
举例说明:aaaaa3aaa2aaa45。a 代表将小灯放入栈中。数字 N 代表将目前栈
顶向下的 N 个资源取出,组成一个环,然后放回栈顶。整个栈的流程如下。
aaaaa → aa[aaa] → aa[aaa]aaa → aa[aaa]a[aa] → aa[aaa]a[aa]aaa →
aa[aaa]a[[aa]aaa]→END
这样就需要栈空间的最大值为8,当其状态为 aa[aaa]a[aa]aaa 时就需要,注
意:环和灯都算一个。
然而还有一个问题。机器人的栈不够大了(真是次品)。所以需要你编一个
指令,使吊灯的设计不变,让指令所需的栈空间越小越好。所谓的设计不变,就
是指:假设在同一层环原来有4 个部件,1234,那么1234、4123、3412等等,只要环的顺序不变就可以。
但是不能有部件增加或者减少。
【输入文件】
输入文件 three.in 每一行一个字符串,代表指令。
【输出文件】
输出文件为three.out 包含一行,代表需要的栈空间
【输入样例】
aaaaa3aaa2aaa45
【输出样例】
6
【数据规模】
100%的数据字符串长度≤10^4
想到了啥呢,刚开始的时候想到:
1. 可以贪心地放置,每次都先把成环的放进去,压缩成环之后就可以省空间啊
2. 能先放大环就不要先放小环
3. 然而他是有顺序的
4. 这道题目有些尴尬
那就继续想了:
假设一个环子的挂的每个小环子都达到最优解,那么这个环子就达到最优解。
换言之,只要计算出了每个环子的最优解,就可以计算出最优解。
第二,每个环子最多有9个子环
那就愉快的分治吧!
对于每个环,贪心和枚举差不了多少,贪心还不一定对,所以就枚举从环的哪个位置开始组装吧
这个字符串给得。。。。让代码实现变得不是很简单啊
我总不能用括号序列吧歪歪歪,那么怎么办呢
可以不可以先找到数字,把串里面的先字母后数字的顺序调换一下。
有难度,为何不直接从后面……对,就从字符串的菊花开始。
每次从后面找到数字之后就处理,用深度优先的递归来处理就好了。
经过两个小时的修改,第二题就完工了。
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=10005;
struct pao{int fi,ls;
};
char s[maxn];
int n,m,k;
pao kong;
pao cal(int cur)
{
pao res=kong;
int nw=s[cur]-'0';
int w=0;
vector po;
for(int i=cur-1;;)
{
if(w==nw)
{
res.ls=i;
break;
}
if(s[i]=='a')
{
w++;
i--;
po.push_back(1);
continue;
}
if(s[i]>='0'&&s[i]<='9')
{
pao wi=cal(i);
i=wi.ls;
po.push_back(wi.fi);
w++;
}
}
int len=po.size();
int tem=INT_MAX;
/*
cout<<"each line 's results:"< hel;
for(int i=0;i>s[sz])
sz++;
pao ans=cal(sz-1);
cout<
注释:
我是不会压位的那种人,所以我就写了结构体
所以说分治的返回值就比较挫
然后我是那种数组运用不太熟练的人,于是我把字符串反过来的时候就用了
出错的地方:
1. 开始的时候sz这个输入的光标就输错了应该从sz-1开始递归的,很尴尬
2. 然后开始的时候,在枚举环的位置的时候,虽然用了%,还是出错,对于for循环的掌握不熟,所以导致gg
3. 我个强迫症,定义变量j之后不知道这玩意等不等于i,就设置成了0,然后完美wa了10分钟。(设置成-1不就行了嘛,然后我就设成了INT_MAX)
4. 样例开始的时候一直是5,后来发现是爆字符串菊花然后vector的位置忘了翻过来,导致失误。
把字符串翻过之后就停手了,因为时间不多了然后我去敲第三题的暴力。
调整
【问题描述】
已给定一个 N 个点 M 条边的有向图,点编号为 1 到 N,第 i 条边为(UI,vi)
权值为 wi。你可以进行一次操作,使得任意一条边的权值变成任意非负整数。要
求进行尽量少的操作次数,使得点 1 到点 N 的最短路径长度变成 c。
题目保证,c 小于在未进行任何操作之前的原图中 1 到 N 的最短路长度。
【输入文件】
输入文件 tweak.in 第一行三个整数,N,M 和 c
接下来 M 行,每行一条边的信息(UI,vi)
和 wi,第 i 行的表述第 i 条边的信息。
保证不会有自环存在,对于不同的 i 和 j,
(ui,vi)不同于(uj,vj) 。
【输出文件】
输出文件 tweak.out 一行一个整数,要进行最少多少次操作才能使得最短路
长度变为 c。
【输入样例】
3 3 3
1 2 3
2 3 3
1 3 8
【输出样例】
1
【样例说明】
将边 1,3 的权值修改为 2 就可以了。
【数据规模】
N≤100
M≤1000
0≤c≤100000
0≤wi≤10000
30%数据满足 M≤20
50%的数据满足 M≤70
以为自己这次模拟赛又要垫底了,当时想死的心都有了,电光火石之间突然第二题瞬间就有把握了?!,整个人都沸腾了!
只剩十分钟了,抄起家伙,准备暴力,思路就是dfs出来所有路径,然后计算需要的减去的次数,记录路径用模拟栈和回溯
如期交上暴力40/100
暴力代码如下,好像不太对,wa了一个,剩下的都是re
注释:
我是不会压位的那种人,所以我就写了结构体
所以说分治的返回值就比较挫
然后我是那种数组运用不太熟练的人,于是我把字符串反过来的时候就用了
出错的地方:
1. 开始的时候sz这个输入的光标就输错了应该从sz-1开始递归的,很尴尬
2. 然后开始的时候,在枚举环的位置的时候,虽然用了%,还是出错,对于for循环的掌握不熟,所以导致gg
3. 我个强迫症,定义变量j之后不知道这玩意等不等于i,就设置成了0,然后完美wa了10分钟。(设置成-1不就行了嘛,然后我就设成了INT_MAX)
4. 样例开始的时候一直是5,后来发现是爆字符串菊花然后vector的位置忘了翻过来,导致失误。
把字符串翻过之后就停手了,因为时间不多了然后我去敲第三题的暴力。
调整
【问题描述】
已给定一个 N 个点 M 条边的有向图,点编号为 1 到 N,第 i 条边为(UI,vi)
权值为 wi。你可以进行一次操作,使得任意一条边的权值变成任意非负整数。要
求进行尽量少的操作次数,使得点 1 到点 N 的最短路径长度变成 c。
题目保证,c 小于在未进行任何操作之前的原图中 1 到 N 的最短路长度。
【输入文件】
输入文件 tweak.in 第一行三个整数,N,M 和 c
接下来 M 行,每行一条边的信息(UI,vi)
和 wi,第 i 行的表述第 i 条边的信息。
保证不会有自环存在,对于不同的 i 和 j,
(ui,vi)不同于(uj,vj) 。
【输出文件】
输出文件 tweak.out 一行一个整数,要进行最少多少次操作才能使得最短路
长度变为 c。
【输入样例】
3 3 3
1 2 3
2 3 3
1 3 8
【输出样例】
1
【样例说明】
将边 1,3 的权值修改为 2 就可以了。
【数据规模】
N≤100
M≤1000
0≤c≤100000
0≤wi≤10000
30%数据满足 M≤20
50%的数据满足 M≤70
以为自己这次模拟赛又要垫底了,当时想死的心都有了,电光火石之间突然第二题瞬间就有把握了?!,整个人都沸腾了!
只剩十分钟了,抄起家伙,准备暴力,思路就是dfs出来所有路径,然后计算需要的减去的次数,记录路径用模拟栈和回溯
如期交上暴力40/100
暴力代码如下,好像不太对,wa了一个,剩下的都是re
注释:
我是不会压位的那种人,所以我就写了结构体
所以说分治的返回值就比较挫
然后我是那种数组运用不太熟练的人,于是我把字符串反过来的时候就用了
出错的地方:
1. 开始的时候sz这个输入的光标就输错了应该从sz-1开始递归的,很尴尬
2. 然后开始的时候,在枚举环的位置的时候,虽然用了%,还是出错,对于for循环的掌握不熟,所以导致gg
3. 我个强迫症,定义变量j之后不知道这玩意等不等于i,就设置成了0,然后完美wa了10分钟。(设置成-1不就行了嘛,然后我就设成了INT_MAX)
4. 样例开始的时候一直是5,后来发现是爆字符串菊花然后vector的位置忘了翻过来,导致失误。
把字符串翻过之后就停手了,因为时间不多了然后我去敲第三题的暴力。
调整
【问题描述】
已给定一个 N个点 M 条边的有向图,点编号为 1 到 N,第 i条边为(UI,vi)
权值为 wi。你可以进行一次操作,使得任意一条边的权值变成任意非负整数。要
求进行尽量少的操作次数,使得点 1到点 N 的最短路径长度变成 c。
题目保证,c小于在未进行任何操作之前的原图中 1 到 N 的最短路长度。
【输入文件】
输入文件 tweak.in第一行三个整数,N,M 和 c
接下来 M行,每行一条边的信息(UI,vi)
和 wi,第 i行的表述第 i 条边的信息。
保证不会有自环存在,对于不同的 i和 j,
(ui,vi)不同于(uj,vj) 。
【输出文件】
输出文件 tweak.out一行一个整数,要进行最少多少次操作才能使得最短路
长度变为 c。
【输入样例】
3 3 3
1 2 3
2 3 3
1 3 8
【输出样例】
1
【样例说明】
将边 1,3的权值修改为 2 就可以了。
【数据规模】
N≤100
M≤1000
0≤c≤100000
0≤wi≤10000
30%数据满足 M≤20
50%的数据满足 M≤70
以为自己这次模拟赛又要垫底了,当时想死的心都有了,电光火石之间突然第二题瞬间就有把握了?!,整个人都沸腾了!
只剩十分钟了,抄起家伙,准备暴力,思路就是dfs出来所有路径,然后计算需要的减去的次数,记录路径用模拟栈和回溯
如期交上暴力40/100
暴力代码如下,好像不太对,wa了一个,剩下的都是re
#include
#include
#include
#include
#include
using namespace std;
struct ed{
int u,v,w;
};
ed a[1005];
int e[105][105];
int t1,t2,t3;
int st[1105];
int tp;
int n,m,c;
int ANS=INT_MAX;
void dfs(int x)
{
if(x==n)
{
priority_queue p;
int sum=0;
for(int i=0;i0)
{
int nw=p.top();
p.pop();
if(nw>n>>m>>c;
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&t1,&t2,&t3);
e[t1][t2]=t3;
}
dfs(1);
cout<
正解在下面
#include
#include
#include
#include
using namespace std;
int n,m,c,cur[111],num,t1,t2,t3;
int l,r,d[104][100111],ans;
struct edge{int to,v,frh;}a[50001];
struct queue{int z,y;}q[5000001];
int main(){
scanf("%d%d%d",&n,&m,&c);
for (int i=1; i<=n; i++)
{
cur[i]=i;
}
num=n;
for (int i=1; i<=m; i++)
{
scanf("%d%d%d",&t1,&t2,&t3);
num++; a[num].to=t2; a[num].v=t3; a[cur[t1]].frh=num; cur[t1]=num;
}
memset(d,-1,sizeof d);
l=r=1; q[1].z=1; q[l].y=0;d[1][0]=0;//
while (l<=r)
{
int t=q[l].z;
while (a[t].frh!=0)
{
t=a[t].frh;
//寻找来边
int nz=q[l].z;
int ny=q[l].y;
int nv=a[t].v;
int nd=d[nz][ny];
int nx=d[a[t].to][q[l].y+a[t].v];
if (nz+nv<=c &&
(nd
总分:
1 100/100
2 100/100
3 40/100