A - Rock-paper-scissors
三个人玩石头剪刀布平局,其中两个出的分别是\(x,y\),求另一个人出的。
\(0\le x,y\le 2\)(\(0,1,2\)分别表示石头,剪刀,布)
输入格式
\(x,y\)
输出格式
用整数格式输出答案。
样例
\(x\) | \(y\) | 输出 |
---|---|---|
\(0\) | \(1\) | \(2\) |
\(0\) | \(0\) | \(0\) |
分析
石头剪刀布这个游戏三人平局只有两种情况(设\(z\)为第三个人出的):
- \(x=y=z\)
- \(x\ne y\ne z\)
所以,我们得出如下递推式:
\(z=\begin{cases}x & (x=y)\\3-x-y & (x\ne y)\end{cases}\)
代码
#include <cstdio>
using namespace std;
int main()
{
int x, y;
scanf("%d%d", &x, &y);
printf("%d\n", x == y? x: 3 - x - y);
return 0;
}
B - Nuts
有\(N\)棵树,第\(i\)棵树上有\(A_i\)颗果实。
一个人会从第\(i\)棵树摘下\(\max(0,A_i-10)\)颗果实。他一共会得到多少果实?
\(1\le N,A_i\le 1000\)
输入格式
\(N\)
\(A_1~\dots~A_N\)
输出格式
输出答案。
样例
样例输入1
3
6 17 28
样例输出1
25
他会从三棵树上分别摘下\(0,7,18\)颗果实,总共\(25\)颗。
样例输入2
4
8 9 10 11
样例输出2
1
他只会从最后一棵树上得到一颗果实。
分析
我们直接按题意模拟即可。
代码
#include <cstdio>
using namespace std;
int main()
{
int n, ans = 0;
scanf("%d", &n);
while(n--)
{
int a;
scanf("%d", &a);
if(a > 10) ans += a - 10;
}
printf("%d\n", ans);
return 0;
}
C - Tour
一个国家有编号为\(1\)至\(N\)的\(N\)座城市和编号为\(1\)至\(M\)的\(M\)条路。
第\(i\)条路从城市\(A_i\)到\(B_i\),且不能用它从城市\(B_i\)到\(A_i\)。
一个人想从起点城市开始旅行并走过若干条路(可以不走,即只游玩一个城市)并到达终点城市。
有多少种合法的起点和终点城市?如果\(X\ne Y\),则\(X\to Y\)和\(Y\to X\)算作两种不同的方案。
\(2\le N\le 2000\)
\(0\le M\le \min(2000,N(N-1))\)
\(1\le A_i,B_i\le N\)
\(A_i\ne B_i\)
\((A_i,B_i)\)互不相同。
输入格式
\(N~M\)
\(A_1~B_1\)
\(\vdots\)
\(A_M~B_M\)
输出格式
输出答案。
样例
样例输入1
3 3
1 2
2 3
3 2
样例输出1
7
有七种可行的旅游方案:\(1\to1\)、\(1\to2\)、\(1\to3\)、\(2\to2\)、\(2\to3\)、\(3\to2\)、\(3\to3\)。
样例输入2
3 0
样例输出2
3
有三种可行的旅游方案:\(1\to1\)、\(2\to2\)、\(3\to3\)。
分析
我们可以把这个国家看成一个简单有向无权图,并把每个节点作为起点跑一遍\(\text{DFS}\),计算总共能到达的结点数即可。
总时间复杂度为\(\mathcal O(n^2)\)。
代码
注意:每次\(\text{DFS}\)之前一定要将\(\mathrm{vis}\)数组清零!
#include <cstdio>
#include <vector>
#define maxn 2005
using namespace std;
vector<int> G[maxn];
bool vis[maxn];
int ans;
void dfs(int v)
{
if(vis[v]) return;
vis[v] = true, ans ++;
for(int u: G[v])
dfs(u);
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
while(m--)
{
int x, y;
scanf("%d%d", &x, &y);
G[--x].push_back(--y);
}
ans = 0;
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
vis[j] = false;
dfs(i);
}
printf("%d\n", ans);
return 0;
}
D - Cooking
两个人要洗\(N\)个碗,其中任意一个人洗第\(i\)个碗需要\(T_i\)分钟。一个人不能同时洗多个碗。
两个人一起洗碗,洗完所有碗至少需要多少分钟?
\(1\le N\le 100\)
\(1\le T_i\le 10^3\)
输入格式
\(N\)
\(T_1~T_2~\dots~T_N\)
输出格式
输出答案。
样例
样例输入1
5
8 3 7 2 5
样例输出1
13
我们可以让两个人分别洗如下的碗:
- 第一个人洗编号为\(5,1\)的碗。总时间为\(T_5+T_1=13\)分钟。
- 第二个人洗编号为\(2,4,3\)的碗。总时间为\(T_2+T_4+T_3=10\)分钟。
总耗时为\(\max(13,10)=13\)分钟。
样例输入2
2
1000 1
样例输出2
1000
样例输入3
9
3 14 15 9 26 5 35 89 79
样例输出3
138
分析
这是一道经典01背包题。
题目可以直接描述为:给定序列\(T\),将其分成两个子序列\(A\)和\(B\)(不要求连续),求最小的\(\min(\sum A,\sum B)\)。
这时,我们发现要使\(\min(\sum A,\sum B)\)最小,由于\(\sum A+\sum B=\sum T\),所以\(|\sum A-\sum B|\)必须也达到最小。
我们可以将\(\sum T\)分成两半,其中一半为\(\lfloor\frac{\sum T}2\rfloor\)。这时,我们可以用dp背包解决此题:从\(T\)中选出一个子序列\(A\),使得\(\sum A\le\lfloor\frac{\sum T}2\rfloor\),这样答案就为\(\sum T-\sum A\)。
代码
#include <cstdio>
#define maxn 105
#define maxv 100005
using namespace std;
int dp[maxv], w[maxn];
inline void setmax(int& x, int y)
{
if(y > x) x = y;
}
int main()
{
int n, v = 0;
scanf("%d", &n);
for(int i=0; i<n; i++)
{
scanf("%d", w + i);
v += w[i];
}
int t = v;
v >>= 1;
for(int i=0; i<n; i++)
for(int j=v; j>=w[i]; j--)
setmax(dp[j], dp[j - w[i]] + w[i]);
printf("%d\n", t - dp[v]);
return 0;
}
E - Rush Hour 2
一个国家有\(N\)座城市和\(M\)条路。城市的编号是\(1\)至\(N\),路的编号则为\(1\)至\(M\)。第\(i\)条路双向连接着城市\(A_i\)和\(B_i\)。
在这个国家中,初始时间为\(0\)。如果你在时间点\(t\)通过公路\(i\),所需时间为\(C_i+\lfloor\frac {D_i} {t+1}\rfloor\)。
一个人想从城市\(1\)到达城市\(N\)。他在每个城市可以停留任意自然数的时间。
求这个人最早到达城市\(N\)的时间。如果无法到达城市\(N\),输出-1
。
\(2\le N\le 10^5\)
\(2\le M\le 10^5\)
\(1\le A_i,B_i\le N\)
\(0\le C_i,D_i\le 10^9\)
输入格式
\(N~M\)
\(A_1~B_1~C_1~D_1\)
\(\vdots\)
\(A_M~B_M~C_M~D_M\)
输出格式
输出答案。
样例
样例输入1
2 1
1 2 2 3
样例输出1
4
我们可以先在城市\(1\)停留至时间\(1\)。然后,我们出发,最终到达时间\(1+2+\lfloor\frac 3 {1+1}\rfloor=4\)。
样例输入2
2 3
1 2 2 3
1 2 2 1
1 1 1 1
样例输出2
3
两个城市之间可能有多条路,一个城市也可能有到自己的路。
样例输入3
4 2
1 2 3 4
3 4 5 6
样例输出3
-1
城市\(1\)到城市\(N\)可能没有路径。
分析
我们可以把输入当成一幅无向图。其实,从一个城市到它自己的路根本没有用,所以我们直接忽略不计。
如果目前时间为\(T\)且我们要从城市\(A_i\)到\(B_i\),我们可以证明,最好的整数出发时间应该是\(\lfloor\sqrt D\rceil-1\)(\(\lfloor x\rceil\)表示\(x\)四舍五入)。
如果\(\lfloor\sqrt D\rceil\le T\),我们应该等到时间\(\lfloor\sqrt D\rceil-1\)再出发;否则,我们直接出发。
这时,我们可以使用Dijkstra最短路算法(使用优先队列优化),这样总时间复杂度就为\(\mathcal O(M\log N)\)。
代码
#include <cstdio>
#include <cmath>
#include <vector>
#include <queue>
#include <tuple>
#define maxn 100005
#define INF 9223372036854775807LL
using namespace std;
using Road = tuple<int, int, int>;
using LL = long long;
using pli = pair<LL, int>;
vector<Road> G[maxn];
LL dist[maxn];
int main()
{
int n, m;
scanf("%d%d", &n, &m);
while(m--)
{
int a, b, c, d;
scanf("%d%d%d%d", &a, &b, &c, &d);
if(--a == --b) continue;
G[a].emplace_back(b, c, d);
G[b].emplace_back(a, c, d);
}
dist[0] = 0LL;
for(int i=1; i<n; i++) dist[i] = INF;
priority_queue<pli, vector<pli>, greater<pli>> q;
q.emplace(0LL, 0);
while(!q.empty())
{
auto [t, u] = q.top(); q.pop();
if(dist[u] != t) continue;
for(auto [v, c, d]: G[u])
{
LL t2 = sqrt((long double) d) - 0.5;
if(t2 < t) t2 = t;
t2 += LL(c) + LL(d) / (t2 + 1LL);
if(t2 < dist[v])
q.emplace(dist[v] = t2, v);
}
}
if(dist[n - 1] == INF) puts("-1");
else printf("%lld\n", dist[n - 1]);
return 0;
}
标签:AtCoder,le,204,输出,int,题解,sum,样例,include
From: https://www.cnblogs.com/stanleys/p/18403472/abc204