2019 ICPC Latin American
2019-2020 ACM-ICPC Latin American Regional Programming Contest
D - Dazzling stars
大意:
平面上有许多点,每个点有权值,问是否存在一条直线,令这条直线按照某个方向移动,使其经过的点权值不下降,且能经过所有点。
思路:
每个点向权值比它小的所有点连成向量,将所有向量的起点移动到原点,如果所有向量都位于某条过原点的直线的一侧,则所求直线存在。将所有向量根据角度排序,判断是否有相邻向量夹角大于180度即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 2000;
const double pi = acos(-1);
int x[N], y[N], b[N];
vector<double> u;
double cal(int x, int y) {
if (x == 0) return y > 0 ? pi / 2 : -pi / 2;
if (y == 0) return x > 0 ? 0 : pi;
double ans = atan(double(y) / x);
if (x > 0) return ans;
return ans + pi;
}
bool check() {
if (u.size() < 2) return true;
double y = u.back() - pi * 2;
for (auto x : u) {
if (x - y + 1e-9 >= pi) return true;
y = x;
}
return false;
}
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> x[i] >> y[i] >> b[i];
for (int j = 0; j < i; j++) {
if (b[i] < b[j])
u.push_back(cal(x[i] - x[j], y[i] - y[j]));
else if (b[i] > b[j])
u.push_back(cal(x[j] - x[i], y[j] - y[i]));
}
}
sort(u.begin(), u.end());
if (check())
cout << "Y\n";
else
cout << "N\n";
return 0;
}
E - Eggfruit Cake
模拟题
#include <bits/stdc++.h>
using namespace std;
#define int long long
int const MAXN = 2e5 + 10;
int n, m, T;
int go[MAXN];
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
string s;
cin >> s;
int l = s.size();
s = s + s;
cin >> n;
int pos = 2 * l;
for (int i = 2 * l - 1; i >= 0; i--) {
if (s[i] == 'E') pos = i;
go[i] = pos;
}
int ans = 0;
for (int i = 0; i < l; i++) {
if (go[i] == 2 * l) continue;
int d = go[i] - i;
if (n - d <= 0) continue;
ans += (n - d);
}
cout << ans;
return 0;
}
F - Fabricating Sculptures
大意:
堆 A 个箱子,第 k 层箱子不能比第 k+1 层箱子多,最下一层有 B 个箱子,求方案数。
思路:
$dp[i][j] \(表示放置了 i 个格子,最上面一层有 j 个格子的方案数,\)dp[i][j]=∑^S_{x=j}dp[i−j][x]∗(x−j+1)$
但是这样就是n^3的复杂度,所以需要维护
\(f1[i][j]=dp[i][1]+dp[i][2]+dp[i][3].....+dp[i][j]\)以及
\(f2[i][j]=dp[i][1]*1+dp[i][2]*2+dp[i][3]*3+....+dp[i][j]*j\)这个两个前缀和,然后更新dp的时候直接\(O(1)\)更新即可
#include <bits/stdc++.h>
using namespace std;
const int N = 5e3 + 5;
#define int LL
typedef long long LL;
LL const mod = 1e9 + 7;
LL dp[N][N], n, m, f1[N][N], f2[N][N];
signed main() {
cin >> m >> n;
dp[m][m] = 1;
f1[m][m] = 1;
f2[m][m] = m;
for (int i = m + 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
dp[i][j] = (-(f1[i - j][m] - f1[i - j][j - 1]) * (j - 1) % mod +
(f2[i - j][m] - f2[i - j][j - 1]) % mod) %
mod;
}
for (int j = 1; j <= m; j++) {
f1[i][j] = (f1[i][j - 1] + dp[i][j]) % mod;
f2[i][j] = (f2[i][j - 1] + dp[i][j] * j % mod) % mod;
}
}
LL res = 0;
for (int i = 1; i <= m; i++) {
res += dp[n][i];
res %= mod;
}
cout << (res + mod) % mod << endl;
return 0;
}
I - Improve SPAM
大意:
一个邮件系统,其中有一些是中转站,每个中转站都会将收到的邮件发给子节点,子节点可能是中转站也可能是用户,现在从一号点出一封邮件,问每个用户总共会收到多少封邮件,以及一共有多少个用户收到邮件
思路:
直接拓扑排序去做即可,每次将父节点的邮件传给子节点
#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read() {
int s = 0, w = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
int const MAXN = 2e3 + 10, MAXM = MAXN * MAXN, mod = 1e9 + 7;
int n, m, T, e[MAXM], ne[MAXM], idx, h[MAXN], val[MAXN], l, din[MAXN], f[MAXN];
void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx++; }
signed main() {
n = read(), l = read();
memset(h, -1, sizeof h);
for (int i = 1, t; i <= l; ++i) {
t = read();
for (int j = 1, k; j <= t; ++j) {
k = read();
add(i, k);
din[k]++;
}
}
int S = 1;
val[S] = 1;
f[1] = 1;
queue<int> q;
for (int i = 1; i <= n; ++i)
if (!din[i]) {
q.push(i);
}
while (q.size()) {
auto t = q.front();
q.pop();
for (int i = h[t]; ~i; i = ne[i]) {
int j = e[i];
val[j] += val[t];
val[j] %= mod;
f[j] |= f[t];
din[j]--;
if (!din[j]) q.push(j);
}
}
int res1 = 0, res2 = 0;
for (int i = l + 1; i <= n; ++i) {
res1 += val[i];
res1 %= mod;
res2 += f[i];
}
cout << res1 % mod << " " << res2;
return 0;
}
K - Know your Aliens
大意:
给出一个字符串,A代表将i带进多项式得到负值,H代表得到正值,现在需要构造一个多项式,使其满足条件
思路:
零点存在定理,如果相邻两个字符不同,那么必然存在零点,这样就可以得到一个零点式表示的多项式,将其化为系数表示即可
#include <bits/stdc++.h>
#define int long long
using namespace std;
int const MAXN = 2e5 + 10;
const double PI = acos(-1);
int n, m, T;
int zero[MAXN], b[MAXN];
int idx = 0;
//从低到高递推求系数,x为零点坐标
void _Get_xi() {
b[1] = 1;
for (int i = 1; i <= idx; i++) {
for (int j = i + 1; j >= 1; j--) {
b[j] = b[j - 1];
}
for (int j = 1; j <= i; j++) {
b[j] += b[j + 1] * zero[i];
}
}
}
signed main() {
string s;
cin >> s;
for (int i = 0; i < s.size() - 1; ++i) {
if (s[i] != s[i + 1]) {
zero[++idx] = 2 * i + 3;
}
}
if (idx != 0)
_Get_xi();
else {
cout << 0 << endl;
if (s[0] == 'H')
cout << 1 << endl;
else
cout << -1 << endl;
return 0;
}
int flag = 1;
cout << idx << endl;
if (s[0] == 'A' && (idx % 2 == 0)) flag = -1;
if (s[0] == 'H' && (idx % 2 == 1)) flag = -1;
for (int i = idx + 1; i >= 1; i--) {
cout << flag * b[i];
if (i > 1) cout << ' ';
flag = -flag;
}
return 0;
}
L - Leverage MDT
大意:
现在有一个n*m的矩阵,元素为B和G,G代表好的点,B代表坏的点,现在可以将每一行翻转(B变G,G变B)或者不翻转,问满足全部由G组成的正方形面积有多大
思路:
因为都可以翻转,那么到底是B和G就没有关系了,所以可以先预处理出每个点左边到他本身相同的字符有多少个
然后对于每列做两次单调栈(类似最大子矩阵)即可
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 5;
typedef long long LL;
int n, m;
int mp[N][N], l[N][N], r[N][N];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
string s;
cin >> s;
s = " " + s;
for (int j = 1; j <= m; j++) {
if (s[j] == s[j - 1])
mp[i][j] = mp[i][j - 1] + 1;
else
mp[i][j] = 1;
}
}
int res = 0;
for (int j = 1; j <= m; j++) {
stack<int> st;
for (int i = 1; i <= n; i++) {
while (!st.empty() && mp[st.top()][j] >= mp[i][j]) st.pop();
if (st.empty())
l[i][j] = 1;
else
l[i][j] = st.top() + 1;
st.push(i);
}
while (!st.empty()) st.pop();
for (int i = n; i >= 1; i--) {
while (!st.empty() && mp[st.top()][j] >= mp[i][j]) st.pop();
if (st.empty())
r[i][j] = n;
else
r[i][j] = st.top() - 1;
st.push(i);
int tmp = min(r[i][j] - l[i][j] + 1, mp[i][j]);
res = max(tmp, res);
}
}
cout << (LL)res * res << endl;
return 0;
}
M - Mountain Ranges
签到
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
typedef long long LL;
int n, x, a[N], res = 0, t = 0;
int main() {
cin >> n >> x;
for (int i = 0; i < n; i++) {
cin >> a[i];
if (i == 0)
t = 1;
else {
if (a[i] - a[i - 1] <= x)
t++;
else
t = 1;
}
res = max(res, t);
}
cout << res << endl;
return 0;
}