赞
踩
三个人玩石头剪刀布平局,其中两个出的分别是 x , y x,y x,y,求另一个人出的。
0 ≤ x , y ≤ 2 0\le x,y\le 2 0≤x,y≤2( 0 , 1 , 2 0,1,2 0,1,2分别表示石头,剪刀,布)
x , y x,y x,y
用整数格式输出答案。
x x x | y y y | 输出 |
---|---|---|
0 0 0 | 1 1 1 | 2 2 2 |
0 0 0 | 0 0 0 | 0 0 0 |
石头剪刀布这个游戏三人平局只有两种情况(设 z z z为第三个人出的):
所以,我们得出如下递推式:
z
=
{
x
(
x
=
y
)
3
−
x
−
y
(
x
≠
y
)
z={x(x=y)3−x−y(x≠y)
#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;
}
有
N
N
N棵树,第
i
i
i棵树上有
A
i
A_i
Ai颗果实。
一个人会从第
i
i
i棵树摘下
max
(
0
,
A
i
−
10
)
\max(0,A_i-10)
max(0,Ai−10)颗果实。他一共会得到多少果实?
1 ≤ N , A i ≤ 1000 1\le N,A_i\le 1000 1≤N,Ai≤1000
N
N
N
A
1
…
A
N
A_1~\dots~A_N
A1 … AN
输出答案。
3
6 17 28
25
他会从三棵树上分别摘下 0 , 7 , 18 0,7,18 0,7,18颗果实,总共 25 25 25颗。
4
8 9 10 11
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; }
一个国家有编号为
1
1
1至
N
N
N的
N
N
N座城市和编号为
1
1
1至
M
M
M的
M
M
M条路。
第
i
i
i条路从城市
A
i
A_i
Ai到
B
i
B_i
Bi,且不能用它从城市
B
i
B_i
Bi到
A
i
A_i
Ai。
一个人想从起点城市开始旅行并走过若干条路(可以不走,即只游玩一个城市)并到达终点城市。
有多少种合法的起点和终点城市?如果
X
≠
Y
X\ne Y
X=Y,则
X
→
Y
X\to Y
X→Y和
Y
→
X
Y\to X
Y→X算作两种不同的方案。
2
≤
N
≤
2000
2\le N\le 2000
2≤N≤2000
0
≤
M
≤
min
(
2000
,
N
(
N
−
1
)
)
0\le M\le \min(2000,N(N-1))
0≤M≤min(2000,N(N−1))
1
≤
A
i
,
B
i
≤
N
1\le A_i,B_i\le N
1≤Ai,Bi≤N
A
i
≠
B
i
A_i\ne B_i
Ai=Bi
(
A
i
,
B
i
)
(A_i,B_i)
(Ai,Bi)互不相同。
N
M
N~M
N M
A
1
B
1
A_1~B_1
A1 B1
⋮
\vdots
⋮
A
M
B
M
A_M~B_M
AM BM
输出答案。
3 3
1 2
2 3
3 2
7
有七种可行的旅游方案: 1 → 1 1\to1 1→1、 1 → 2 1\to2 1→2、 1 → 3 1\to3 1→3、 2 → 2 2\to2 2→2、 2 → 3 2\to3 2→3、 3 → 2 3\to2 3→2、 3 → 3 3\to3 3→3。
3 0
3
有三种可行的旅游方案: 1 → 1 1\to1 1→1、 2 → 2 2\to2 2→2、 3 → 3 3\to3 3→3。
我们可以把这个国家看成一个简单有向无权图,并把每个节点作为起点跑一遍
DFS
\text{DFS}
DFS,计算总共能到达的结点数即可。
总时间复杂度为
O
(
n
2
)
\mathcal O(n^2)
O(n2)。
注意:每次 DFS \text{DFS} DFS之前一定要将 v i s \mathrm{vis} 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; }
两个人要洗
N
N
N个碗,其中任意一个人洗第
i
i
i个碗需要
T
i
T_i
Ti分钟。一个人不能同时洗多个碗。
两个人一起洗碗,洗完所有碗至少需要多少分钟?
1
≤
N
≤
100
1\le N\le 100
1≤N≤100
1
≤
T
i
≤
1
0
3
1\le T_i\le 10^3
1≤Ti≤103
N
N
N
T
1
T
2
…
T
N
T_1~T_2~\dots~T_N
T1 T2 … TN
输出答案。
5
8 3 7 2 5
13
我们可以让两个人分别洗如下的碗:
总耗时为 max ( 13 , 10 ) = 13 \max(13,10)=13 max(13,10)=13分钟。
2
1000 1
1000
9
3 14 15 9 26 5 35 89 79
138
这是一道经典01背包题。
题目可以直接描述为:给定序列
T
T
T,将其分成两个子序列
A
A
A和
B
B
B(不要求连续),求最小的
min
(
∑
A
,
∑
B
)
\min(\sum A,\sum B)
min(∑A,∑B)。
这时,我们发现要使
min
(
∑
A
,
∑
B
)
\min(\sum A,\sum B)
min(∑A,∑B)最小,由于
∑
A
+
∑
B
=
∑
T
\sum A+\sum B=\sum T
∑A+∑B=∑T,所以
∣
∑
A
−
∑
B
∣
|\sum A-\sum B|
∣∑A−∑B∣必须也达到最小。
我们可以将
∑
T
\sum T
∑T分成两半,其中一半为
⌊
∑
T
2
⌋
\lfloor\frac{\sum T}2\rfloor
⌊2∑T⌋。这时,我们可以用dp背包解决此题:从
T
T
T中选出一个子序列
A
A
A,使得
∑
A
≤
⌊
∑
T
2
⌋
\sum A\le\lfloor\frac{\sum T}2\rfloor
∑A≤⌊2∑T⌋,这样答案就为
∑
T
−
∑
A
\sum T-\sum A
∑T−∑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; }
一个国家有
N
N
N座城市和
M
M
M条路。城市的编号是
1
1
1至
N
N
N,路的编号则为
1
1
1至
M
M
M。第
i
i
i条路双向连接着城市
A
i
A_i
Ai和
B
i
B_i
Bi。
在这个国家中,初始时间为
0
0
0。如果你在时间点
t
t
t通过公路
i
i
i,所需时间为
C
i
+
⌊
D
i
t
+
1
⌋
C_i+\lfloor\frac {D_i} {t+1}\rfloor
Ci+⌊t+1Di⌋。
一个人想从城市
1
1
1到达城市
N
N
N。他在每个城市可以停留任意自然数的时间。
求这个人最早到达城市
N
N
N的时间。如果无法到达城市
N
N
N,输出-1
。
2
≤
N
≤
1
0
5
2\le N\le 10^5
2≤N≤105
2
≤
M
≤
1
0
5
2\le M\le 10^5
2≤M≤105
1
≤
A
i
,
B
i
≤
N
1\le A_i,B_i\le N
1≤Ai,Bi≤N
0
≤
C
i
,
D
i
≤
1
0
9
0\le C_i,D_i\le 10^9
0≤Ci,Di≤109
N
M
N~M
N M
A
1
B
1
C
1
D
1
A_1~B_1~C_1~D_1
A1 B1 C1 D1
⋮
\vdots
⋮
A
M
B
M
C
M
D
M
A_M~B_M~C_M~D_M
AM BM CM DM
输出答案。
2 1
1 2 2 3
4
我们可以先在城市 1 1 1停留至时间 1 1 1。然后,我们出发,最终到达时间 1 + 2 + ⌊ 3 1 + 1 ⌋ = 4 1+2+\lfloor\frac 3 {1+1}\rfloor=4 1+2+⌊1+13⌋=4。
2 3
1 2 2 3
1 2 2 1
1 1 1 1
3
两个城市之间可能有多条路,一个城市也可能有到自己的路。
4 2
1 2 3 4
3 4 5 6
-1
城市 1 1 1到城市 N N N可能没有路径。
我们可以把输入当成一幅无向图。其实,从一个城市到它自己的路根本没有用,所以我们直接忽略不计。
如果目前时间为
T
T
T且我们要从城市
A
i
A_i
Ai到
B
i
B_i
Bi,我们可以证明,最好的整数出发时间应该是
⌊
D
⌉
−
1
\lfloor\sqrt D\rceil-1
⌊D
⌉−1(
⌊
x
⌉
\lfloor x\rceil
⌊x⌉表示
x
x
x四舍五入)。
如果
⌊
D
⌉
≤
T
\lfloor\sqrt D\rceil\le T
⌊D
⌉≤T,我们应该等到时间
⌊
D
⌉
−
1
\lfloor\sqrt D\rceil-1
⌊D
⌉−1再出发;否则,我们直接出发。
这时,我们可以使用Dijkstra最短路算法(使用优先队列优化),这样总时间复杂度就为
O
(
M
log
N
)
\mathcal O(M\log N)
O(MlogN)。
#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; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。