A Good morning(模拟)
过水
void solve()
{
int h1, m1, h2, m2;
cin >> h1 >> m1 >> h2 >> m2;
if(h1 == h2)
{
if(m1 == m2) puts("Takahashi");
else if(m1 < m2) puts("Takahashi");
else puts("Aoki");
}
else if(h1 < h2) puts("Takahashi");
else puts("Aoki");
}
B Mex(模拟)
过水
void solve()
{
int n, x;
cin >> n;
for(int i = 0; i < n; i++)
cin >> x, mp[x] = 1;
for(int i = 0; i <= 2000; i++)
if(mp[i] == 0) {cout << i << endl; return;}
}
C Choose Elements(DP)
Description:
给定两个数组 a, b
要求构造出一个数组X满足以下要求
1 X_i = a_i || X_i = b_i
2 abs(X_i - X_i+1) <= k
Solution:
那我们很容易可以想到 这题就是对于当前的i去枚举一下i + 1的两条路是否能够走通
画出一条搜索树 可以得知DFS复杂度 2^n
那我们就考虑一下在搜索的过程中 我们做了那些无用功导致复杂度那么高
简单判断 当一个点不可达的时候 这个点就已经无效了 不需要用它向后拓展了
然后想办法记录当前状态 递推并用bool数组记录下是否可达 最后询问终点的状态即可
那么一个状态DP的雏形就出现了 对于每一个可达点 我们去判断他的下一步的两个点是否可达
Code:
const int N = 200010;
int a[N], b[N];
bool dpa[N], dpb[N]; //a[i]是否可达 b[i]是否可达
void solve()
{
int n, k;
cin >> n >> k;
for(int i = 1; i <= n; i++)
cin >> a[i];
for(int i = 1; i <= n; i++)
cin >> b[i];
dpa[1] = true;
dpb[1] = true;
for(int i = 1; i <= n - 1; i++)
{
if(dpa[i])
{
if(abs(a[i + 1] - a[i]) <= k) dpa[i + 1] = true;
if(abs(b[i + 1] - a[i]) <= k) dpb[i + 1] = true;
}
if(dpb[i])
{
if(abs(a[i + 1] - b[i]) <= k) dpa[i + 1] = true;
if(abs(b[i + 1] - b[i]) <= k) dpb[i + 1] = true;
}
}
if(dpa[n] || dpb[n]) cout << "Yes" << endl;
else cout << "No" << endl;
}
D Polynomial division(多项式除法 + 模拟)
Description:
给出两个多项式 求其商
Solution:
模拟竖式计算 重要的是因为小心/0的情况
Code:
void solve()
{
int n, m;
cin >> n >> m;
vector<int> a(n + 1), c(n + m + 1), b(m + 1);
for(int i = 0; i <= n; i++)
cin >> a[i];
for(int i = 0; i <= n + m; i++)
cin >> c[i];
for(int i = m; i >= 0; i --) //枚举b的同时也是枚举c的[n + 1, c + m + 1]
{
b[i] = c[n + i] / a[n];
for(int j = 0; j <= n; j++)
c[i + j] -= b[i] * a[j];
}
for(auto x : b) cout << x << ' ';
cout << endl;
}
E Wrapping Chocolate(排序 + 二分)
Description:
给出n个巧克力 m个盒子 当盒子的长和宽都大于等于巧克力的时候(长和宽不能颠倒) 可以装下巧克力 请问是否能装下所有的巧克力
Solution:
因为N=2e5 应该是要用一个nlog的做法过掉 然后又跟大小有关系 于是我就打算往排序想
对巧克力和盒子都小到大排序 然后双指针判断 然后一直写挂
总感觉应该是枚举漏了情况 思维不够紧密
正解是 以宽大到小排序 用multiset存下 宽大于等于当前巧克力的box 然后在集合里二分查找第一个长度大于等于巧克力长度的盒子 若找不到 证明后面当前巧克力无法放入任何盒子中 失败
Code:
void solve()
{
int n, m;
cin >> n >> m;
vector<array<int,2> > box(m), a(n);
for(int i = 0; i < n; i++)
cin >> a[i][0];
for(int i = 0; i < n; i++)
cin >> a[i][1];
for(int i = 0; i < m; i++)
cin >> box[i][0];
for(int i = 0; i < m; i++)
cin >> box[i][1];
sort(a.begin(), a.end(), greater());
sort(box.begin(), box.end(), greater());
multiset<int> s; //存长度
for(int i = 0, j = 0; i < n; i ++) //遍历巧克力
{
while(j < m && box[j][0] >= a[i][0]) //当宽度大于等于当前巧克力
{
s.insert(box[j][1]);
j ++;
}
auto it = s.lower_bound(a[i][1]);
if(it == s.end()) //因为在当前大于等于巧克力宽度的box里都找不到了 那后面更找不到
{
cout << "No\n";
return;
}
s.erase(it);
}
cout << "Yes\n";
}
ACM编程技巧解析
本文解析了五道ACM竞赛题目,包括模拟、DP、多项式除法等算法的应用,并详细介绍了每道题目的解题思路及代码实现。
601

被折叠的 条评论
为什么被折叠?



