A.One-dimensional Japanese Crossword(Codeforces 721A)
思路
本題是讓我們統計題給字符串中連續的‘
代碼
#include <bits/stdc++.h>
using namespace std;
int n;
string s;
vector <int> ans;
int main() {
ios::sync_with_stdio(false);
cin >> n >> s;
for(int i = 0; i < s.size(); i++) {
if(s[i] == 'W') {
s[i] = ' ';
}
}
stringstream ss(s);
while(ss >> s) {
ans.push_back(s.size());
}
cout << ans.size() << endl;
for(int i = 0; i < ans.size(); i++) {
cout << ans[i] << ' ';
}
return 0;
}
B. Passwords(Codeforces 721B)
思路
由於密碼是按照長度順序輸入,而同長度的密碼隨機輸入。
因此最好的情況是輸入完長度小於真實密碼的密碼之後(設其共有
最壞的情況是輸入完長度小於真實密碼的密碼之後將與真實密碼長度相同的其它密碼(設其有
代碼
#include <bits/stdc++.h>
using namespace std;
const int maxn = 200;
int n, k, a, b, len, sum, num, cnt[maxn];
string s;
int main() {
ios::sync_with_stdio(false);
cin >> n >> k;
for(int i = 0; i < n; i++) {
cin >> s;
cnt[s.size()]++;
}
cin >> s;
len = s.size();
for(int i = 1; i < len; i++) {
sum += cnt[i];
}
num = cnt[len];
a = sum / k * 5 + sum + 1;
b = (sum + num - 1) / k * 5 + sum + num;
cout << a << ' ' << b << endl;
return 0;
}
C.Journey(Codeforces 721C)
思路
因爲本題的圖是個有向無環聯通圖,又需要在這個圖上求某個最大值。所以自然想到用動態規劃來解決。但是因爲動態規劃需要一個“序”,而這個圖是無序的,因此想到從點
定義
爲了按照主人公行走的順序輸出點的編號,在更新
在這個算法下,所有的點都只被訪問一次,被訪問的點都只會做
代碼
#include <bits/stdc++.h>
using namespace std;
typedef pair <int, int> p;
const int maxn = 5010;
bool vis[maxn];
int n, m, T, u, v, w, ans, cur, x[maxn][maxn], d[maxn][maxn];
vector <p> G[maxn];
// 在拓撲排序的同時動態規劃
void dfs(int u) {
vis[u] = true;
for(int i = 0; i < G[u].size(); i++) {
p& node = G[u][i];
int v = node.first;
int w = node.second;
if(vis[v] == false) {
dfs(v);
}
for(int j = 2; j <= n; j++) {
if(d[u][j] > d[v][j-1] + w) {
// 更新數組
d[u][j] = d[v][j-1] + w;
// 記錄路徑
x[u][j] = v;
}
}
}
}
int main() {
scanf("%d%d%d", &n, &m, &T);
while(m--) {
scanf("%d%d%d", &u, &v, &w);
G[u].push_back(p(v, w));
}
// 初始化
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
d[i][j] = T + 1;
}
}
d[n][1] = 0;
// 拓撲排序
dfs(1);
for(int j = n; j >= 1; j--) {
if(d[1][j] <= T) {
ans = j;
break;
}
}
printf("%d\n", ans);
// 按行走順序輸出
cur = 1;
for(int i = ans; i >= 1; i--) {
printf("%d ", cur);
cur = x[cur][i];
}
return 0;
}
D.Maxim and Array(Codeforces 721D)
思路
序列的積由兩個值唯一決定,一個是積的負號,另一個是積的絕對值。
當積的符號爲正的時候,只要將序列中絕對值最小的元素不斷減小(直到積的符號爲負)就能夠減小積的大小。
當積的符號爲負的時候,只要將積的絕對值增大就能減小積的大小。爲了讓積的絕對值增大,可以找到序列中絕對值最小的元素,增加其絕對值即可。
那麼我們可以在模擬k減小的同時維護積的符號
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair <ll, int> p;
const int maxn = 2e5 + 5;
// sign的初始值爲0,表示積爲非負數
int n, k, x, v, d, sign, flag;
ll a[maxn];
priority_queue < p, vector<p>, greater<p> > pq;
int main() {
scanf("%d%d%d", &n, &k, &x);
for(int i = 0; i < n; i++) {
scanf("%I64d", &a[i]);
// 將絕對值插入堆中,附加位置信息
pq.push(p(abs(a[i]), i));
// 當a[i]爲負數時修改積的符號
sign ^= (a[i] < 0);
}
// 模擬數組的減小過程
while(k--) {
p tmp = pq.top();
pq.pop();
v = tmp.first;
d = tmp.second;
// 記錄修改之前的符號
flag = (a[d] < 0);
// 修改序列的元素的值
a[d] += (sign ^ flag ? 1 : -1) * x;
// 若符號改變則修改sign
sign ^= flag ^ (a[d] < 0);
pq.push(p(abs(a[d]), d));
}
for(int i = 0; i < n; i++) {
printf("%I64d ", a[i]);
}
return 0;
}
(其它題目略)