TYZ群赛 8/21解题报告

 


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<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<math.h>
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<<ans<<endl;
	return 0;
}

第二题’:

名字叫“第三题”(。。。。。。。。。。。。。。)

原型是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<iostream>
#include<limits.h>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<stack>
#include<vector>
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<int> 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:"<<endl;
	for(int i=0;i<len;i++)
	cout<<po[i]<<" ";
	cout<<endl;
	*/
	stack<int> hel;
	for(int i=0;i<len;i++)
	{
		hel.push(po[i]);
	}
	for(int i=0;i<len;i++)
	{
		int zc=hel.top();
		po[i]=zc;
		hel.pop();
	}
	/*
	cout<<"each line 's results:"<<endl;
	for(int i=0;i<len;i++)
	cout<<po[i]<<" ";
	cout<<endl;
	*/
	for(int i=0;i<len;i++)
	{
		int sum=0;
		int tm=0;
		bool shou=1;
		for(int j=INT_MAX;j!=i;)	
			{
				if(shou)
				{
					j=i;
					shou=0;
				}
				tm=max(tm,po[j]+sum);
				sum++;
				j=(j+1)%len;
			}
		tem=min(tem,tm);			
	}
	res.fi=tem;
	//cout<<"but the final results is :"<<tem<<endl;
	return res;
}
int sz=1;
int main()//请养成从主函数开始阅读的好习惯!
{
	freopen("three.in","r",stdin);
	freopen("three.out","w",stdout);
	while(cin>>s[sz])
	sz++;
	pao ans=cal(sz-1);
	cout<<ans.fi<<endl;
	return 0;
}
 

注释:

我是不会压位的那种人,所以我就写了结构体

所以说分治的返回值就比较挫

然后我是那种数组运用不太熟练的人,于是我把字符串反过来的时候就用了

出错的地方:

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,然后完美wa10分钟。(设置成-1不就行了嘛,然后我就设成了INT_MAX

4.    样例开始的时候一直是5,后来发现是爆字符串菊花然后vector的位置忘了翻过来,导致失误。

把字符串翻过之后就停手了,因为时间不多了然后我去敲第三题的暴力。

调整

【问题描述】

已给定一个 N个点 M 条边的有向图,点编号为 1 N,第 i条边为(UIvi

权值为 wi。你可以进行一次操作,使得任意一条边的权值变成任意非负整数。要

求进行尽量少的操作次数,使得点 1到点 N 的最短路径长度变成 c

题目保证,c小于在未进行任何操作之前的原图中 1 N 的最短路长度。

【输入文件】

输入文件 tweak.in第一行三个整数,NM c

接下来 M行,每行一条边的信息(UIvi

wi,第 i行的表述第 i 条边的信息。

保证不会有自环存在,对于不同的 i j

uivi)不同于(ujvj) 。

【输出文件】

输出文件 tweak.out一行一个整数,要进行最少多少次操作才能使得最短路

长度变为 c

【输入样例】

3 3 3

1 2 3

2 3 3

1 3 8

【输出样例】

1

【样例说明】

将边 13的权值修改为 2 就可以了。

【数据规模】

N100

M1000

0c100000

0wi10000

30%数据满足 M20

50%的数据满足 M70

 

以为自己这次模拟赛又要垫底了,当时想死的心都有了,电光火石之间突然第二题瞬间就有把握了?!,整个人都沸腾了!

只剩十分钟了,抄起家伙,准备暴力,思路就是dfs出来所有路径,然后计算需要的减去的次数,记录路径用模拟栈和回溯

如期交上暴力40/100

暴力代码如下,好像不太对,wa了一个,剩下的都是re

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<queue>
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<int> p;
		int sum=0;
		for(int i=0;i<tp;i++)
		{
			p.push(st[i]);
			sum+=st[i];
		}
		int ned=sum-c;
		int ans=0;
		while(ned>0)
		{
			int nw=p.top();
			p.pop();
			if(nw<ned)
			{
				ned-=nw;
				ans++;
			}
			else
			{
				ned=0;
				ans++;
				ANS=min(ANS,ans);
				return;
			}
		}
	}
	
	for(int i=1;i<=n;i++)
	{
		if(e[x][i])
		{
			st[tp]=e[x][i];
			tp++;
			dfs(i);
			tp--;
		}
	}
}
int main()
{
	freopen("tweak.in","r",stdin);
	freopen("tweak.out","w",stdout);
	cin>>n>>m>>c;
	for(int i=1;i<=m;i++)
	{
		scanf("%d %d %d",&t1,&t2,&t3);
		e[t1][t2]=t3;
	}
	dfs(1);
	cout<<ANS<<endl;
	return 0;
}


正解在下面

#include<cstdio>
#include<cstring>
#include<climits>
#include<iostream>
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<nx||nx==-1))
                  {
                    nx=nd;
                    r++; q[r].z=a[t].to; q[r].y=q[l].y+a[t].v; 
                    
                  }
                  //由于上一步修改了部分,所有的变量重新定义(反正复制粘贴) 
                   nz=q[l].z;
				  ny=q[l].y;
				  nv=a[t].v;
				  nd=d[nz][ny];
				  nx=d[a[t].to][q[l].y+a[t].v];
				 int ns=d[q[l].z][q[l].y];
				int nm=d[a[t].to][q[l].y];
                if (ns+1<nm||nm==-1)
                
                  {
                    d[a[t].to][q[l].y]=nm=ns+1;
                    r++; q[r].z=a[t].to; q[r].y=q[l].y;
                  }
            }
          l++;
      }
    ans=INT_MAX;
    for (int i=0; i<=c; i++)
        if (d[n][i]<ans && d[n][i]!=-1)
           ans=d[n][i];
    cout<<ans<<endl; 
    return 0;
}


 

总分:

1 100/100

2 100/100

3 40/100

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值