题目链接:AtCoder Beginner Contest 362
A. Buy a Pen
tag:签到
B. Right Triangle
tag:模拟
C. Right Triangle
tag:贪心
Description:给定 n n n对整数 l i , r i l_i, r_i li,ri;求一个整数序列,满足 l i < = x i < = r i l_i <= x_i <= r_i li<=xi<=ri,且 ∑ i n x i = 0 \sum_{i}^{n}x_i = 0 ∑inxi=0;如果没有则输出 − 1 -1 −1。
Solution:先判断是否有解,令 m i = ∑ i n l i , m a = ∑ i n r i mi = \sum_{i}^{n}l_i, ma = \sum_{i}^{n}r_i mi=∑inli,ma=∑inri。如果 m i < = 0 且 m a > = 0 mi <= 0 且 ma >= 0 mi<=0且ma>=0有解,否则无解。
- 先假设所有值都取最小值,则 s u m = m i sum = mi sum=mi,然后开始枚举当前位置的取值,看是否能令 s u m = 0 sum = 0 sum=0,否则当前值取最大值,继续向后枚举。
Competing:想到了如何判断是否有解,但是没想到贪心求解。
void solve(){
cin >> n;
int mi = 0, ma = 0;
vector<pii> a(n);
for (int i = 0; i < n; i ++){
int l, r;
cin >> l >> r;
a[i] = {l, r};
mi += l;
ma += r;
}
if (mi > 0 || ma < 0){
cout << "No\n";
}
else{
cout << "Yes\n";
for (int i = 0; i < n; i ++){ // 刚开始假设所有值都取最小值
if (mi == 0){
for (int j = i; j < n; j ++){
cout << a[j].fi << " ";
}
return;
}
mi -= a[i].fi; // 开始选择第i个值
if (a[i].fi <= -mi && -mi <= a[i].se){
cout << -mi << " ";
for (int j = i + 1; j < n; j ++){
cout << a[j].fi << " ";
}
return;
}
mi += a[i].se;
cout << a[i].se << " ";
}
}
}
D. Shortest Path 3
tag:Dijkstra
Description:给定一个图,每个点,边都有权值,求所有从起点 1 1 1到 i i i的路径长度(边的权值 + 点的权值)。
Solution:Dijkstra板子,将权值加上点的权值即可。
void solve(){
cin >> n >> m;
vector g(n + 5, vector<pii>());
vector<int> dis(n + 5, 1e15), st(n + 5);
vector<int> a(n + 5);
for (int i = 1; i <= n; i ++)
cin >> a[i];
for (int i = 0; i < m; i ++){
int x, y, w;
cin >> x >> y >> w;
g[x].eb(w, y);
g[y].eb(w, x);
}
auto dijkstra = [&](int u) -> void{
dis[u] = a[u];
priority_queue<pii, vector<pii>, greater<pii>> qu;
qu.ep(dis[u], u);
while (qu.size()){
auto [w, y] = qu.top();
qu.pop();
if (st[y])
continue;
st[y] = true;
for (auto [ww, yy] : g[y]){
if (a[yy] + ww + w < dis[yy]){
dis[yy] = ww + w + a[yy];
qu.ep(dis[yy], yy);
}
}
}
};
dijkstra(1);
for (int i = 2; i <= n; i ++){
cout << dis[i] << " ";
}
}
E. Count Arithmetic Subsequences
tag: dp
Description:给定一个数组
a
a
a,求不同长度的等差数列的个数(
1
<
=
l
e
n
<
=
a
.
s
i
z
e
(
)
1 <= len <= a.size()
1<=len<=a.size())。a.size() <= 80
。
Solution:因为 a a a的长度很小,所有我们可以考虑 d p dp dp。
-
状态表示:显然需要有长度和公差,然后需要一个位置。所有我们使用 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k],表示终点为 i i i,长度为 j j j,公差为 k k k的所有等差数列的集合。
-
状态转移: d p [ i ] [ j ] [ k ] + = d p [ x ] [ j − 1 ] [ k ] , x < i 且 a [ k ] − a [ x ] = k dp[i][j][k] += dp[x][j - 1][k], x < i 且 a[k] - a[x] = k dp[i][j][k]+=dp[x][j−1][k],x<i且a[k]−a[x]=k。
-
初始化:初始化长度为 2 2 2的所有答案;注意到公差的范围很大,我们使用 m a p map map进行离散化。
int dp[100][100][6500];
map<int, int> d;
void solve(){
cin >> n;
vector<int> a(n);
int cnt = 1;
for (int i = 0; i < n; i ++)
cin >> a[i];
for (int i = 0; i < n; i ++)
for (int j = 0; j < n; j ++){
if (!d[a[i] - a[j]])
d[a[i] - a[j]] = cnt ++; // 离散化
}
for (int i = 0; i < n; i ++){
for (int j = 0; j < i; j ++){
dp[i][2][d[a[i] - a[j]]] ++; // 初始化长度为2的
}
for (int j = 0; j < i; j ++)
for (int k = 3; k <= i + 1; k ++){
dp[i][k][d[a[i] - a[j]]] += dp[j][k - 1][d[a[i] - a[j]]];
dp[i][k][d[a[i] - a[j]]] %= mod;
}
}
for (int k = 1; k <= n; k++){
if (k == 1){
cout << n << " ";
continue;
}
int ans = 0;
for (int i = 0; i < n; i++){
for (int j = 1; j <= cnt; j++){
ans += dp[i][k][j];
ans %= mod;
}
}
cout << ans << ' ';
}
}