外培D2题解

我我我我真的好好好好好瞎+蠢,居然没把语言改成C++,弄成CE爆零,想一巴掌抽死自己╮(╯﹏╰)╭,但是真实分数190也不是很好,只能安慰自己——这样我进步会很大(ノへ ̄、),加油(๑•̀ㅂ•́)و✧。

1420. 佳肴 (Standard IO)——暴搜

Time Limits: 1000 ms  Memory Limits: 65536 KB

Goto ProblemSet

Description

  佳肴就是非常美味的菜的意思,佳肴最关键的是选择好原料。
  现在有N种原料,每种原料都有酸度S和苦度B两个属性,当选择多种原料时,总酸度为每种原料的酸度之积,总苦度为每种原料的苦度之和。
  正如大家所知,佳肴是既不酸也不苦的,因为要保证所选的原料使得总酸度和总苦度差的绝对值最小。
  由于佳肴不能只有水,所以必须至少选择一种佳肴。

Input

  输入第一行包含一个整数N(1<=N<=10),表示原料的种数。
  接下来N行每行包含两个用一个空格隔开的整数,分别表示酸度和苦度。
  输入数据保证如果所有原料都选上,总酸度和总苦度不会超过10^9。

Output

  输出总酸度和总苦度最小的差。

Sample Input

输入1:
1
3 10

输入2:
2
3 8
5 8

输入3:
4
1 7
2 6
3 8
4 9

Sample Output

输出1:
7

输出2:
1

输出3:
1

Data Constraint Hint

1<=N<=10

【样例解释】
  样例3中选择最后三种原料,这样总酸度为2×3×4=24,总苦度为6+8+9=23,差为1。

思路

N那么小,暴搜O(2^{n})可以过

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 15
int n,ans=int(1e9+1);
struct node
{
	int s,k;
}a[MAXN];
inline int abss(int x)
{
	if(x<0)x=-x;
	return x;
}
void dfs(int x,bool d,int ss,int sk)
{
	if(x>n)return;
	if(d)
	{
		ss*=a[x].s;
		sk+=a[x].k;
		ans=min(ans,abss(ss-sk));
	}
	dfs(x+1,1,ss,sk);
	dfs(x+1,0,ss,sk);
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d%d",&a[i].s,&a[i].k);
	dfs(1,1,1,0);
	dfs(1,0,1,0);
	printf("%d",ans);
}

1308. 取数游戏 (Standard IO)

Time Limits: 1000 ms  Memory Limits: 65536 KB

Goto ProblemSet

Description

  Alice想让Bob陪他去看《唐山大地震》,但由于Bob是个很感性的人,怕流泪不想去,但又不好意思以这个作为拒绝的理由,便提出玩一个游戏。
  N个正整数围成一圈,规则如下:
  •两个玩家轮流取数;
  •最开始先手的玩家可以取任意一个数x;
  •从第二步开始当前玩家只能取x(上一玩家刚刚取的数)左右两边相邻的数;
  •直到取完所有的数,游戏结束;
  •取得较多奇数的玩家获胜。
  Bob为了显示大度,让Alice先取,但他忘了自己和Alice都是绝顶聪明之人,现在Alice请你帮他计算第一步有多少种取法使得最终获得胜利。

Input

  第一行包含一个整数N(1<=N<=100),表示数的个数。第二行包含N个正整数,每个数都在1到1000之间,任意两个数互不相同。

Output

  输出Alice第一步有多少种取法。

Sample Input

输入1:
3
3 1 5

输入2:
4
1 2 3 4

输入3:
8
4 10 5 2 9 8 1 7

Sample Output

输出1:
3

输出2:
2

输出3:
5

Data Constraint

1<=N<=100

思路

 

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 2*105
int n,a[MAXN],ans,s[MAXN];
int f[MAXN][MAXN];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		a[i]%=2;
		a[n+i]=a[i];
		s[i]=s[i-1]+a[i];
	}
	for(int i=1;i<=n;i++)
		s[n+i]=s[n+i-1]+a[i];
	for(int k=1;k<=n;k++)//枚举起始点 
	{
		memset(f,0,sizeof(f));
		for(int i=1;i<=n*2;i++)
			f[i][i]=a[i];
		for(int i=k+n-1;i>k;i--)
			for(int j=i+1;j<=k+n-1;j++)
				f[i][j]=s[j]-s[i-1]-min(f[i+1][j],f[i][j-1]);
		if(s[k+n]-s[k]-f[k+1][k+n-1]>f[k+1][k+n-1])ans++;
	}
	printf("%d",ans);
}

1381. 删除 (Standard IO)

Time Limits: 1000 ms  Memory Limits: 65536 KB

Goto ProblemSet

Description

  Alice上化学课时又分心了,他首先画了一个3行N列的表格,然后把数字1到N填入表格的第一行,保证每个数只出现一次,另外两行他也填入数字1到N,但不限制每个数字的出现次数。
  Alice现在想删除若干列使得每一行排完序后完全一样,编程计算最少需要删除多少列。

Input

  第一行包含一个整数N(1<=N<=100000),表示表格的列数。
  接下来三行每行包含N个整数,每个数在1到N之间,而且第一行的数互不相同。

Output

  输出最少需要删除的列数。

Sample Input

输入1:
7
5 4 3 2 1 6 7
5 5 1 1 3 4 7
3 7 1 4 5 6 2

输入2:
9
1 3 5 9 8 6 2 4 7
2 1 5 6 4 9 3 4 7
3 5 1 9 8 6 2 8 7

Sample Output

输出1:
4

输出2:
2

Data Constraint Hint

1<=N<=100000

【样例解释】
  例1中Alice需要删除第2、4、6、7这四列,然后每行排完序都是1、3、5。
【数据范围】
  40%的数据N<=100
  70%的数据N<=10000

思路

 

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 100005
int n,ans;
int a[MAXN],b[MAXN],c[MAXN];
int f1[MAXN],f2[MAXN];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)
		scanf("%d",&b[i]),f1[b[i]]++;
	for(int i=1;i<=n;i++)
		scanf("%d",&c[i]),f2[c[i]]++;
	bool pd=1;
	while(pd)
	{
		pd=0;
		for(int i=1;i<=n;i++)
			if(a[i]>0&&(f1[a[i]]==0||f2[a[i]]==0))
			{
				f1[b[i]]--;
				f2[c[i]]--;
				ans++;
				a[i]=0;
				pd=1;
			}
	}
	//for(int i=1;i<=n;i++)
	//	if(a[i]==0)ans++;
	printf("%d",ans);
}

1382. 区间 (Standard IO)

Time Limits: 1000 ms  Memory Limits: 65536 KB 

Goto ProblemSet

Description

  Alice收到一些很特别的生日礼物:区间。即使很无聊,Alice还是能想出关于区间的很多游戏,其中一个是,Alice从中选出最长的不同区间的序列,其中满足每个区间必须在礼物中,另序列中每个区间必须包含下一个区间。
  编程计算最长序列的长度。

Input

  输入文件第一行包含一个整数N(1<=N<=100000),表示区间的个数。
  接下来N行,每行两个整数A和B描述一个区间(1<=A<=B<=1000000)。

Output

  输出满足条件的序列的最大长度。

Sample Input

输入1:
3
3 4
2 5
1 6

输入2:
5
10 30
20 40
30 50
10 60
30 40

输入3:
6
1 4
1 5
1 6
1 7
2 5
3 5

Sample Output

输出1:
3

输出2:
3

输出3:
5

Data Constraint Hint

1<=N<=100000 1<=A<=B<=1000000

【样例解释】
  例3中可以找到长度为5的区间序列是:[1,7]、[1,6]、[1,5]、[2,5]、[3,5]

思路

按A从大到小sort后用O(nlog(n))做B的最长上升子序列(用二分)。

LIS的O(nlog(n))算法

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 100005
int n,ans;
struct node
{
	int s,e;
}a[MAXN];
bool cmp(node a,node b)
{
	if(a.s==b.s)return a.e<b.e;
	return a.s>b.s;
}
int f[MAXN],d[MAXN];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d%d",&a[i].s,&a[i].e);
	sort(a+1,a+n+1,cmp);
//	printf("\n\n");
//	for(int i=1;i<=n;i++)
//		printf("%d %d\n",a[i].s,a[i].e);
	d[1]=a[1].e;
	int cnt=1;
	for(int i=2;i<=n;i++)
		if(a[i].e>=d[cnt])d[++cnt]=a[i].e;
		else
		{
			int k=upper_bound(d+1,d+cnt+1,a[i].e)-d;
		//	printf("*%d*%d\n",k,i);
			d[k]=a[i].e;
		}
	printf("%d",cnt);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
06-01
这道题是一道典型的费用限制最短路题目,可以使用 Dijkstra 算法或者 SPFA 算法来解决。 具体思路如下: 1. 首先,我们需要读入输入数据。输入数据中包含了道路的数量、起点和终点,以及每条道路的起点、终点、长度和限制费用。 2. 接着,我们需要使用邻接表或邻接矩阵来存储图的信息。对于每条道路,我们可以将其起点和终点作为一个有向边的起点和终点,长度作为边权,限制费用作为边权的上界。 3. 然后,我们可以使用 Dijkstra 算法或 SPFA 算法求解从起点到终点的最短路径。在这个过程中,我们需要记录到每个点的最小费用和最小长度,以及更新每条边的最小费用和最小长度。 4. 最后,我们输出从起点到终点的最短路径长度即可。 需要注意的是,在使用 Dijkstra 算法或 SPFA 算法时,需要对每个点的最小费用和最小长度进行松弛操作。具体来说,当我们从一个点 u 经过一条边 (u,v) 到达另一个点 v 时,如果新的费用和长度比原来的小,则需要更新到达 v 的最小费用和最小长度,并将 v 加入到优先队列(Dijkstra 算法)或队列(SPFA 算法)中。 此外,还需要注意处理边权为 0 或负数的情况,以及处理无法到达终点的情况。 代码实现可以参考以下样例代码: ```c++ #include <cstdio> #include <cstring> #include <queue> #include <vector> using namespace std; const int MAXN = 1005, MAXM = 20005, INF = 0x3f3f3f3f; int n, m, s, t, cnt; int head[MAXN], dis[MAXN], vis[MAXN]; struct Edge { int v, w, c, nxt; } e[MAXM]; void addEdge(int u, int v, int w, int c) { e[++cnt].v = v, e[cnt].w = w, e[cnt].c = c, e[cnt].nxt = head[u], head[u] = cnt; } void dijkstra() { priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q; memset(dis, 0x3f, sizeof(dis)); memset(vis, 0, sizeof(vis)); dis[s] = 0; q.push(make_pair(0, s)); while (!q.empty()) { int u = q.top().second; q.pop(); if (vis[u]) continue; vis[u] = 1; for (int i = head[u]; i != -1; i = e[i].nxt) { int v = e[i].v, w = e[i].w, c = e[i].c; if (dis[u] + w < dis[v] && c >= dis[u] + w) { dis[v] = dis[u] + w; q.push(make_pair(dis[v], v)); } } } } int main() { memset(head, -1, sizeof(head)); scanf("%d %d %d %d", &n, &m, &s, &t); for (int i = 1; i <= m; i++) { int u, v, w, c; scanf("%d %d %d %d", &u, &v, &w, &c); addEdge(u, v, w, c); addEdge(v, u, w, c); } dijkstra(); if (dis[t] == INF) printf("-1\n"); else printf("%d\n", dis[t]); return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值