文章目录
UCF Local Programming Contest 2019(Practice)
A. Buying in Bulk
题意: 签到
题解: 签到
代码:
#include<bits/stdc++.h>
using namespace std;
int t;
int main()
{
cin >> t;
while (t--)
{
/* code */
int c, p;
cin >> c >> p;
if (c == 1) cout << p << "\n";
else {
cout << c * p - (c - 1) * 2 << "\n";
}
}
return 0;
}
B. Are We Stopping Again?
题意:
题解:
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> vec;
int main(){
int n, a, b;
cin >> n >> a >> b;
for(int i = a; i < n; i += a){
vec.push_back(i);
// cout << i << endl;
}
for(int i = b; i < n; i += b){
vec.push_back(i);
// cout << i << endl;
}
sort(vec.begin(), vec.end());
vec.erase(unique(vec.begin(), vec.end()), vec.end());
printf("%d\n", vec.size());
return 0;
}
C. Spell Checker
题意:
题解: 大模拟
代码:
/*
*/
#include<iostream>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <unordered_map>
#include <set>
#include <cstring>
using namespace std;
int const N = 110;
int n, m;
// 记录每个单词可以从哪个类型变换过来
struct OO
{
vector<string> ori_string;
vector<int> idx;
}oo;
unordered_map<string, OO> wrong; // wrong记录每个单词的错误类型和错误变换形式
unordered_map<int, string> tt; // tt记录每种类型的输出文字
unordered_map<string, int> orignal, exi; // orignal记录单词是否在词典中出现,exi记录单词是否是原词典中单词的错误变形
string ss[N]; // 初始词典
int main()
{
ios::sync_with_stdio(false);
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
// 1.缺失 2.增加 3.替换 4.交换
tt[1] = "ONE LETTER OMITTED FROM ";
tt[2] = "ONE LETTER ADDED TO ";
tt[3] = "ONE LETTER DIFFERENT FROM ";
tt[4] = "TWO LETTERS TRANSPOSED IN ";
// 读入初始词典
cin >> n;
for (int i = 0; i < n; ++i)
{
cin >> ss[i];
orignal[ss[i]] = 1; // 记录每个单词是否在原来的词典中出现
}
// 记录词典中每个单词可以变成哪个单词
for (int i = 0; i < n; ++i)
{
string str = ss[i];
//缺失
string ori = str;
for (int i = 0; i < str.size(); ++i)
{
str.erase(i, 1);
if (orignal.count(str))
{
str = ori;
continue;
}
wrong[str].ori_string.push_back(ori);
wrong[str].idx.push_back(1);
exi[str] = 1;
str = ori;
}
// 增加
for (int i = 0; i <= str.size(); ++i)
{
for (int j = 0; j < 26; ++j)
{
string t = "";
t += ('a' + j);
str.insert(i, t);
if (orignal.count(str))
{
str = ori;
continue;
}
wrong[str].ori_string.push_back(ori);
wrong[str].idx.push_back(2);
exi[str] = 1;
str = ori;
}
}
// 替换
for (int i = 0; i < str.size(); ++i)
{
for (int j = 0; j < 26; ++j)
{
str[i] = ('a' + j);
if (str == ori) continue;
if (!orignal.count(str))
{
wrong[str].ori_string.push_back(ori);
wrong[str].idx.push_back(3);
exi[str] = 1;
}
str = ori;
}
}
// 相邻交换
for (int i = 0; i < str.size() - 1; ++i)
{
swap(str[i], str[i + 1]);
if (orignal.count(str))
{
str = ori;
continue;
}
wrong[str].ori_string.push_back(ori);
wrong[str].idx.push_back(4);
exi[str] = 1;
swap(str[i], str[i + 1]);
}
}
// 读入询问
cin >> m;
for (int i = 0; i < m; ++i)
{
string str;
cin >> str;
cout << str << "\n";
// 如果在原来的词典中出现,输出CORRECT
if (orignal.count(str))
{
cout << "CORRECT\n\n";
continue;
}
else // 如果不在原来词典中出现,判断是否属于原词典中的单词发生错误
{
if (!exi[str]) // 如果不是单词错误,输出UNKNOWN
{
cout << "UNKNOWN\n\n";
continue;
}
else // 属于单词错误
{
set<string> e;
for (int t = 0; t < wrong[str].idx.size(); ++t) // 打印可能的错误原因
{
if (!e.count(tt[wrong[str].idx[t]] + wrong[str].ori_string[t]))
{
cout << tt[wrong[str].idx[t]] << wrong[str].ori_string[t] << "\n";
e.insert(tt[wrong[str].idx[t]] + wrong[str].ori_string[t]);
}
}
cout << "\n";
}
}
}
return 0;
}
D. Circles Inside a Square
题意:
题解: 简单计算几何
代码:
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
using namespace std;
const double PI = 3.1415926535;
int main(){
int t;
cin >> t;
while(t--){
double r;
cin >> r;
double tmp = 2.0 * r + 2.0 * r * 1.732050807568877;
tmp = tmp * 0.70710678118;
double ans = (tmp + 2 * r) * (tmp + 2 * r);
printf("%.5lf\n", ans);
}
return 0;
}
E. Anya's Favorite CD
题意:
题解: 区间dp
代码:
/*
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int const N = 1e3 + 10;
int t, s;
LL f[N][11];
int choice[N][11];
int cnt[N];
int main()
{
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
cin >> t >> s;
memset(f, 0x3f, sizeof f);
for (int i = 0; i < 11; ++i) f[0][i] = 0;
cnt[0] = 1;
for (int i = 1; i <= s; ++i)
{
scanf("%d", &cnt[i]);
for (int j = 1; j <= cnt[i]; ++j)
{
scanf("%d", &choice[i][j]);
for (int k = 1; k <= cnt[i - 1]; ++k)
{
LL step;
if (choice[i - 1][k] + 1 < choice[i][j])
step = min(choice[i][j] - choice[i - 1][k] - 1, choice[i - 1][k] + 1 + t - choice[i][j] );
else step = min(choice[i - 1][k] + 1 - choice[i][j], choice[i][j] + t - 1 - choice[i - 1][k]);
f[i][j] = min(f[i][j], f[i - 1][k] + step);
}
}
}
LL res = 1e18;
for (int i = 1; i <= cnt[s]; ++i)
{
res = min(res, f[s][i]);
}
printf("%lld\n", res);
return 0;
}
F. Sub Matrix Sum
题意: 给定一个 1 0 5 ∗ 1 0 5 10^5 * 10^5 105∗105的矩形,要求找到一个子矩形,使得子矩形所有元素权值和大于等于S,打印最小的子矩形规模(元素个数)。所有矩形内的元素大小在 − 1 0 9 ∼ 1 0 9 -10^9 \sim 10^9 −109∼109, 矩形规模 r ∗ c < = 1 0 5 r * c <= 10^5 r∗c<=105。
题解: 如果所有元素全部为正数,那么直接使用二维尺取维护即可。但是本题的元素存在负值,因此前缀和失去了单调性,所以这个方法不可行。但是我们可以用单调栈维护到当前点单调的前缀和,这样就可以二分了。因此我们固定i行和j行后,枚举第k列,在单调栈里二分sum[k]-S的最大的位置,然后不断维护区间最小值即可。
代码:
#include <bits/stdc++.h>
using namespace std;
#define N 100005
const int INF = 0x3f3f3f3f;
typedef long long LL;
vector<vector<LL> > v;
vector<LL> st; // 单调栈
LL sum[N], s;
int r, c;
// 计算当确定了i行和j行后,满足条件的矩形的最小宽度
int solve() {
int res = INF;
st.clear();
st.push_back(0);
for (int i = 1; i <= c; i++) { // 枚举每列
int l = 0, r = st.size() - 1;
LL tmp = sum[i] - s;
int Ans = -1;
while (l <= r) { // 二分sum[i] - S的位置,单调栈维护了到当前点的单调的前缀和
int Mid = l + r >> 1;
if (sum[st[Mid]] <= tmp) {
l = Mid + 1;
Ans = st[Mid];
} else
r = Mid - 1;
}
if (Ans != -1) res = min(res, i - Ans);
while (!st.empty() && sum[st[st.size() - 1]] >= sum[i]) st.pop_back();
st.push_back(i);
}
if (res == INF) res = -1;
return res;
}
int main() {
scanf("%d %d %lld", &r, &c, &s);
v.clear();
// 让小的是r
if (r < c) {
v.resize(r + 1);
for (int i = 0; i <= r; i++) v[i].resize(c + 1);
for (int i = 1; i <= r; i++)
for (int j = 1; j <= c; j++) scanf("%lld", &v[i][j]);
} else {
v.resize(c + 1);
for (int i = 0; i <= c; i++) v[i].resize(r + 1);
for (int i = 1; i <= r; i++)
for (int j = 1; j <= c; j++) scanf("%lld", &v[j][i]);
swap(c, r);
}
// 维护列的前缀和
for (int i = 0; i <= c; i++) v[0][i] = 0;
for (int i = 1; i <= r; i++)
for (int j = 1; j <= c; j++) v[i][j] = v[i - 1][j] + v[i][j];
int Ans = r * c + 1;
// 枚举i行和j行
for (int i = 1; i <= r; i++)
for (int j = i; j <= r; j++) {
sum[0] = 0;
// 计算i行和j行之间列的元素和
for (int k = 1; k <= c; k++)
sum[k] = v[j][k] - v[i - 1][k];
for (int k = 1; k <= c; k++) sum[k] += sum[k - 1];
// 计算最小的宽度
int ret = solve();
if (ret == -1)
continue;
else
Ans = min(Ans, ret * (j - i + 1));
}
if (Ans == r * c + 1)
printf("-1\n");
else
printf("%d\n", Ans);
return 0;
}