首页 > 其他分享 >2019 CSP-J

2019 CSP-J

时间:2024-01-15 23:01:29浏览次数:26  
标签:10 int price leq 2019 CSP dp dis

2019 CSP-J

P5660 数字游戏(语法)

题意

给定一个长度最大为 \(8\) 的01字符串,求字符串中有多少个 \(1\)。

题解

#include<bits/stdc++.h>
using namespace std;
/*====================*/
#define endl "\n"
/*====================*/
typedef long long lnt;
/*====================*/
void Solve(void)
{
	string str; 
	cin >> str;
	int ans = 0;
	for (auto c : str)
	{
		if (c == '1')
		{
			ans++;
		}
	}
	cout << ans << endl;
}
/*====================*/
int main()
{
#ifndef ONLINE_JUDGE
	freopen("IN.txt", "r+", stdin);
#endif
	ios::sync_with_stdio(false);
	cin.tie(NULL), cout.tie(NULL);
	int T = 1; //cin >> T;
	while (T--)Solve();
	return 0;
}

P5661 公交换乘(模拟,STL)

题意

搭乘一次地铁后可以获得一张优惠票,有效期为 \(45\) 分钟,在有效期内(即:\(t_{bus} - t_{subway} \leq 45\))可以消耗这张优惠票,免费搭乘一次票价不超过地铁票价的公交车。

搭乘公交车时,如果可以使用优惠票一定会使用优惠票;如果有多张优惠票满足条件,则优先消耗获得最早的优惠票。

现给出交通出行记录,计算花费。

数据规模与约定

对于 \(100\%\) 的数据,\(n \leq 10^5\),\(t_i \leq 10^9\),\(1 \leq price_i \leq 1000\)。

题解

将乘车记录按时间排序(本题已经有序)。

遍历乘车记录,边遍历边维护当前时间还有效的优惠票。因为有效期最大为 \(45\) 分钟,而数据保证不存在两次乘车记录时间相同,所以当前还有效的优惠票最多 \(45\) 张。

从有效的优惠票中查找是否有能够使用的优惠票,如果有,就删去该优惠票,否则计入答案。

总结一下对有效优惠票的维护需要支持的操作:

  1. 以时间为关键字有序。
  2. 查找时间最早的,满足条件的优惠票。
  3. 删除优惠票。

我们使用 set 维护即可。

如果本题数据范围改成 \(t_i \leq 10^{18}\),有效期为 \(10^5\) 分钟,该怎么做?

上面做法时间复杂度是正确的原因是最多有 \(45\) 张优惠票。现在增强后最多有 \(10^5\) 张优惠票,遍历查找会 TLE。

所以我们只需要优化查找过程就可以。使用平衡树,线段树等数据结构代替 set 维护优惠票即可。

#include<bits/stdc++.h>
using namespace std;
/*====================*/
#define endl "\n"
/*====================*/
typedef long long lnt;
/*====================*/
const int N = 1e5 + 10;
/*====================*/
int n;
/*====================*/
struct Record
{
	int transportation;
	int price;
	int t;
	Record(int _transportation = 0, int _price = 0, int _t = 0)
	{
		transportation = _transportation;
		price = _price;
		t = _t;
	}
	friend bool operator<(const Record& a, const Record& b)
	{
		return a.t < b.t;
	}
};
Record record[N];
/*====================*/
void Solve(void)
{
	do
	{
		cin >> n;
		for (int i = 1; i <= n; ++i)
		{
			int transportation; cin >> transportation;
			int price; cin >> price;
			int t; cin >> t;
			record[i] = Record(transportation, price, t);
		}
	} while (false);//读入

	do
	{
		int ans = 0;
		set<Record>lib;//优惠票
		for (int i = 1; i <= n; ++i)
		{
			if (record[i].transportation == 0)//地铁
			{
				ans += record[i].price;
				lib.insert(record[i]);
			}
			if (record[i].transportation == 1)//公交车
			{
				//清除过期票
				while (!lib.empty() && record[i].t - lib.begin()->t > 45)
				{
					lib.erase(lib.begin());
				}
				//寻找最早有效票
				bool flag = false;//默认没有使用票
				for (auto it = lib.begin(); it != lib.end(); ++it)
				{
					if (record[i].price <= it->price)
					{
						flag = true;
						lib.erase(it);
						break;
					}
				}
				//更新答案
				if (!flag)
				{
					ans += record[i].price;
				}
			}
		}
		cout << ans << endl;
	} while (false);//模拟
}
/*====================*/
int main()
{
#ifndef ONLINE_JUDGE
	freopen("IN.txt", "r+", stdin);
#endif
	ios::sync_with_stdio(false);
	cin.tie(NULL), cout.tie(NULL);
	int T = 1; //cin >> T;
	while (T--)Solve();
	return 0;
}

P5662 纪念品(dp,滚动数组)

题意

给定未来 \(T\) 天 \(N\) 种物品每天买入与卖出的价格。

每天对于每种物品可以买入与卖出无限次。

每天卖出物品换回的金币可以当日用于买入物品。

每天买入的物品可以当日用于卖出换回金币。

第 \(T\) 天卖出所有物品换回金币。

求第 \(T\) 天能获得的最大金币数量。

数据规模与约定

对于 \(100\%\) 的数据,\(T \leq 100, N \leq 100, M \leq 10^3\),所有价格 \(1 \leq P_{i,j} \leq 10^4\)。

数据保证任意时刻,持有的金币数不超过 \(10^4\)。

题解

首先,直觉经验告诉我们这题很可能是 dp,那我们不妨考虑一下到底是不是 dp。

我们发现,每天的交易其实是前一天和当前天转移的过程,而前一天的状态确定的时候,我们不在乎更前的天数是怎么操作的。

有了最优子结构,有了转移,就有了 dp。现在我们思考状态怎么设计。

如果把每种货物的数量都放到状态里,时间和空间都无法承受,因为货物的组合是乘法原理。

我们发现,当前天可以卖出再买入,也可以买入再卖出。所以我们可以把前一天剩下的货物,在当前天全部卖出变现。而如果这一天需要再买一些货物留到之后的天数去卖,我们可以直接买。因为卖出和买入的价格是一致的,不会发生亏损。

于是我们不需要具体记录每种货物到底各有多少个,我们只需要记录前一天到底最多能给我多少钱就可以。

而每一种货物的数量和其他种货物的数量无关,只和我今天花了多少钱买货物有关。

于是我们可以设计出状态 \(dp_{i,j,k}\),在第 \(i\) 天,一共花了 \(k\) 元买前 \(j\) 种货物,能在第 \(i+1\) 天卖出多少钱。

那么考虑转移,第 \(j\) 种货物有买和不卖两种决策。

\(dp_{i,j,k}=max\begin{cases}dp_{i,j-1,k}&不买第j种货物\\dp_{i,j,k-price_{i,j}}+(price_{i+1,j}-price_{i,j})&买第j种货物,多花了price_{i,j}元,第{i+1}天多赚了(price_{i+1,j}-price_{i,j})元\end{cases}\)

然后我们发现第一维天数可以优化掉,跑天数轮就可以。

于是状态变成 \(dp_{i,j}\) ,当前天花了 \(j\) 元钱买前 \(i\) 种物品,第二天全部卖出能赚的最大钱数。

\(dp_{i,j}=max\begin{cases}dp_{i-1,j}&不买第i种货物\\dp_{j,k-price_{today,i}}+差价&买第i种货物\end{cases}\)

然后我们发现这个是完全背包的转移式,把第一维前 \(i\) 种货物也给滚动掉。最终就是跑若干天完全背包。详见代码。

思考一下,dp 的初值是什么?

#include<bits/stdc++.h>
using namespace std;
/*====================*/
#define endl "\n"
/*====================*/
typedef long long lnt;
/*====================*/
const int D = 1e2 + 10;
const int N = 1e2 + 10;
const int V = 1e4 + 10;
/*====================*/
int d, n, m;
int price[D][N];
int dp[V];
/*====================*/
void Solve(void)
{
	do
	{
		cin >> d >> n >> m;
		for (int i = 1; i <= d; ++i)
		{
			for (int j = 1; j <= n; ++j)
			{
				cin >> price[i][j];
			}
		}
	} while (false);//读入

	do
	{
		for (int day = 1; day < d; ++day)
		{
			dp[0] = m;
			//memset(dp, 0, sizeof(dp));
			//这句话可以删除,因为dp压缩掉一维后求的是最大值。
			//而最大值单调不减,所以初始值为0和初始值为原先的最大值并没有影响。
			//因为dp过程中最大值只会更大,不会更小,所以只要初始值转移是对的即可。
			int maxmoney = m;
			for (int i = 1; i <= n; ++i)
			{
				for (int j = price[day][i]; j <= m; ++j)
				{
					maxmoney = max(maxmoney, dp[j] = max(dp[j], dp[j - price[day][i]] + price[day + 1][i] - price[day][i]));
				}
			}
			m = maxmoney;
		}
		cout << m << endl;
	} while (false);//dp
}
/*====================*/
int main()
{
#ifndef ONLINE_JUDGE
	freopen("IN.txt", "r+", stdin);
#endif
	ios::sync_with_stdio(false);
	cin.tie(NULL), cout.tie(NULL);
	int T = 1; //cin >> T;
	while (T--)Solve();
	return 0;
}

P5663 加工零件(最短路)

题意

工厂里有 \(n\) 位工人,工人们从 \(1 \sim n\) 编号。某些工人之间存在双向的零件传送带。保证每两名工人之间最多只存在一条传送带。

如果 \(x\) 号工人想生产一个被加工到第 \(L\,(L \gt 1)\) 阶段的零件,则所有与 \(x\) 号工人有传送带直接相连的工人,都需要生产一个被加工到第 \(L - 1\) 阶段的零件(但 \(x\) 号工人自己无需生产第 \(L - 1\) 阶段的零件)。

如果 \(x\) 号工人想生产一个被加工到第 \(1\) 阶段的零件,则所有与 \(x\) 号工人有传送带直接相连的工人,都需要为 \(x\) 号工人提供一个原材料。

轩轩是 \(1\) 号工人。现在给出 \(q\) 张工单,第 \(i\) 张工单表示编号为 \(a_i\) 的工人想生产一个第 \(L_i\) 阶段的零件。轩轩想知道对于每张工单,他是否需要给别人提供原材料。

数据规模与约定

对于 \(100\%\) 的数据,\(1 \leq n, m, q \leq 10^5\),\(1 \leq L \leq 10^9\)。

题解

不难发现题目给了一张无向图。

考虑 \(x\) 号点到 \(1\) 号点的路径:

  1. 存在 \(x \rightarrow y \rightarrow ... \rightarrow 1\) 这样一条路径。

  2. 存在 \(x \rightarrow y \rightarrow x \rightarrow y \rightarrow ... \rightarrow 1\) 这样一条路径。

  3. 存在 \(x \rightarrow y \rightarrow x \rightarrow y \rightarrow x \rightarrow y \rightarrow ... \rightarrow 1\) 这样一条路径。

  4. \(...\)

这说明对于 \(x\) 号点到 \(1\) 号点,所有长度为 \(dis+2*k\),\(k\) 为任意非负整数的路径都存在。

于是我们只需要判断 \(1\) 号点到所有点的最短路是否小于等于 \(L\) 即可。

但是这样存在一个问题,那就是,所有的 \(dis+2*k\) 奇偶性和 \(dis\) 一致。

所以我们要求出最短的奇数 \(dis\) 和最短的偶数 \(dis\)。

我们求最短路的时候在状态里记录一下奇偶性即可。

#include<bits/stdc++.h>
using namespace std;
/*====================*/
#define endl "\n"
/*====================*/
typedef long long lnt;
/*====================*/
const int N = 1e5 + 10;
const int M = 1e5 + 10;
const int Q = 1e5 + 10;
/*====================*/
int n, m, q;
/*====================*/
namespace _Graph
{
	struct Edge
	{
		int u, v;
		Edge(int _u = 0, int _v = 0)
		{
			u = _u, v = _v;
		}
		int node(int x)const
		{
			return x == u ? v : u;
		}
	};
	/*====================*/
	int cntedge;
	Edge edge[M];
	vector<int>G[N];
	/*====================*/
	void AddEdge(int u, int v)
	{
		edge[++cntedge] = Edge(u, v);
		G[u].push_back(cntedge);
		G[v].push_back(cntedge);
	}
}
/*====================*/
namespace _Dijkstra
{
	using namespace _Graph;
	/*====================*/
	struct Unit
	{
		int tag, v, w;
		Unit(int _tag = 0, int _v = 0, int _w = 0)
		{
			tag=_tag,v = _v, w = _w;
		}
		friend bool operator<(const Unit& a, const Unit& b)
		{
			return a.w > b.w;
		}
	};
	/*====================*/
	int dis[2][N]; bool vis[2][N];
	/*====================*/
	void Init(int s)
	{
		memset(dis, 0X3F, sizeof(dis));
		memset(vis, false, sizeof(vis));
		priority_queue<Unit>q;
		q.push(Unit(0, s, dis[0][s] = 0));
		while (!q.empty())
		{
			int cur = q.top().v, tag = q.top().tag; q.pop();
			if (vis[tag][cur])continue; vis[tag][cur] = true;
			for (int i = 0; i < G[cur].size(); ++i)
			{
				int nxt = edge[G[cur][i]].node(cur);
				if (dis[tag ^ 1][nxt] > dis[tag][cur] + 1)
				{
					dis[tag ^ 1][nxt] = dis[tag][cur] + 1;
					q.push(Unit(tag ^ 1, nxt, dis[tag ^ 1][nxt]));
				}
			}
		}
	}
}
/*====================*/
void Solve(void)
{
	cin >> n >> m >> q;
	for (int i = 1; i <= m; ++i)
	{
		int u, v; cin >> u >> v;
		_Graph::AddEdge(u, v);
	}
	_Dijkstra::Init(1);
	for (int i = 1; i <= q; ++i)
	{
		int a, l; cin >> a >> l;
		if (_Dijkstra::dis[l % 2][a] <= l)
		{
			cout << "Yes" << endl;
		}
		else
		{
			cout << "No" << endl;
		}
	}
}
/*====================*/
int main()
{
#ifndef ONLINE_JUDGE
	freopen("IN.txt", "r+", stdin);
#endif
	ios::sync_with_stdio(false);
	cin.tie(NULL), cout.tie(NULL);
	int T = 1; //cin >> T;
	while (T--)Solve();
	return 0;
}

标签:10,int,price,leq,2019,CSP,dp,dis
From: https://www.cnblogs.com/ProtectEMmm/p/17966604

相关文章

  • 2019 CSP-J 江西
    2019CSP-J江西P5681面积(语法)题意求出边长为\(a\)的正方形与长宽分别为\(b,c\)的矩形哪一个面积更大。题解#include<bits/stdc++.h>usingnamespacestd;/*====================*/#defineendl"\n"/*====================*/typedeflonglonglnt;/*===========......
  • 2020 CSP-J
    P7071优秀的拆分(语法)题意给定一个正整数,输出二进制拆分。如果这个数是奇数输出-1。数据规模与约定对于\(100\%\)的数据,\(1\len\le10^7\)。题解#include<bits/stdc++.h>usingnamespacestd;/*====================*/#defineendl"\n"/*====================*/......
  • 2021 CSP-J
    P7909分糖果(数学)题意给定\(n,l,r\),求一个数\(x\),当\(l\lex\ler\)时,最大的\(x\bmodn\)。数据规模与约定对于\(100\%\)的数据,\(1\len\lel\ler\le10^9\)。题解假设\(l=K_l*n+R_l,r=K_r*n+R_r,x=K_x*n+R_x\)。我们要求\(R_x\)尽......
  • 2019 CSP-J
    P5660数字游戏(语法)题意给定一个长度最大为\(8\)的01字符串,求字符串中有多少个\(1\)。题解#include<bits/stdc++.h>usingnamespacestd;/*====================*/#defineendl"\n"/*====================*/typedeflonglonglnt;/*====================*/voidSo......
  • 2023 CSP-J
    P9748小苹果(模拟)题意\(n\)个苹果从左到右排成一列,编号为从\(1\)到\(n\)。每天从左侧第\(1\)个苹果开始,每隔\(2\)个苹果拿走\(1\)个苹果。求出多少天能拿完所有的苹果,编号为\(n\)的苹果是在第几天被拿走。数据规模与约定对于\(100\%\)的数据,\(1\len\le10^9......
  • 2022 CSP-J
    P8813乘方(数学,模拟)题意给定两个数\(a,b\),如果\(a^b\le10^9\),输出\(a^b\)的值。否则输出\(-1\)。数据规模与约定对于\(100\%\)的数据,\(1\lea,b\le10^9\)。题解记得开longlong。如果\(a=1\),那么无论\(b\)是多少结果都是\(1\)。如果\(a\ne1\),那么\(a......
  • [极客大挑战 2019]HTTP 1
    [极客大挑战2019]HTTP1审题看到题目页面发现没啥东西,直接看源码发现了,Secret.php进入查看题目,发现又是一道跟着提示达到条件的题目知识点跟着题目走。解题题目说不是来自https://Sycsecret.buuoj.cn的访问,但是我们发现没有Referer,所以我们加入表示来源看到回显,他......
  • WindowsServer 2019安装域服务
    WindowsServer2019安装域服务导航目录WindowsServer2019安装域服务导航一、重命名主控服务器固定IP地址重命名域控服务器二、登录并创建服务三、检验安装域服务一、重命名主控服务器固定IP地址右击电脑右下角网络的标志,点击打开“网络和internet”设置,在屏幕中间的......
  • [极客大挑战 2019]LoveSQL 1
    [极客大挑战2019]LoveSQL1审题又是一道SQL题,还和上面Easy_SQL是一个系列的题。知识点SQL注入之联合查询。知识点详解联合查询基础讲解:union联合查询定义是:可以使用UNION操作符,将多个查询结果,按行进行纵向合并。基本语法SELECT<字段名>FROM<表名>UNIONSELECT<字......
  • P5501 [LnOI2019] 来者不拒,去者不追 题解
    题目链接:来者不拒,去者不追直接在线查询题目所给的式子是很困难的,我们考虑单点考察贡献。对于一个已经确定的式子,我们发现加入一个数或者删除一个数的贡献如图所示:如图所示,在原有的序列为\((1,2,3)\)当中,我们加入新的\(2\)进去,我们观察到每个数的贡献的变化是这样,比\(2\)......