Codeforces Round #750 (Div. 2)
A. Luntik and Concerts
c要么為奇數要么為偶數,同時a和b都大於1,如果c為奇數的話拿出一個1一個2就可以把所有的3都平均分了,如果是偶數的話所有的3能直接平均分。同理再把b盡力平均分掉...
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#define ll long long
#define pb push_back
using namespace std;
int main() {
int T;
cin >> T;
//T = 1;
while(T--) {
ll a, b, c;
cin >> a >> b >> c;
int mn = min(a, b);
if((mn + c) & 1) {
mn--;
a -= mn;
b -= mn;
} else {
a -= mn;
b -= mn;
}
b &= 1;
if(b) {
if(a >= 2) a -= 2;
cout << (a & 1) << endl;
} else {
cout << (a & 1) << endl;
}
}
return 0;
}
B. Luntik and Subsequences
比A還簡單..首先找出所有的0和1,答案就是1的個數乘以2的零的個數的次方(組合數考慮每個0選或者不選,\(C_n^0+C_n^1+..C_n^n = 2^n\))。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#define ll long long
#define pb push_back
using namespace std;
ll n, a[105], sum;
const int N = 100;
ll fpow(ll a, ll b) {
ll ans = 1;
for(; b; b >>= 1) {
if(b & 1) ans = ans * a;
a = a * a;
}
return ans;
}
int main() {
int T;
cin >> T;
//T = 1;
while(T--) {
cin >> n;
sum = 0;
int one = 0, zero = 0;
for(int i = 1; i <= n; i++) {
cin >> a[i];
sum += a[i];
if(a[i] == 1) one++;
else if(a[i] == 0) zero++;
}
cout << one * (fpow(2, zero)) << endl;
}
return 0;
}
C. Grandma Capa Knits a Scarf
寫了一波非常麻煩的做法,首先a~z枚舉刪掉的字符char,然后在原串剔除這個字符得到新串同時記錄新串每個位置的字符在原串的位置,如果這個串是回文的話就從新串兩邊同時對稱地枚舉位置,統計在原串中前面兩個位置中間的char的數量以及后面兩個位置中間的char的數量,作差就是要刪掉的字符數。每一輪不斷累加要刪掉的字符數再更新答案即可。距離來說,對於"abcaacab",如果枚舉到a,得到的新串就是"bccb",在原串的位置分別是1, 2, 5和7,此時枚舉新串,第一輪枚舉的新串位置是0和3(即兩個b),對應原串就是1和7,1之前有1個a,7之后沒有a,因此要刪掉的a的數目就是1;第二輪枚舉的新串位置是1和2(即兩個c),對應原串就是2和5,2之前1之后有0個a,5之后7之前有一個a,因此要刪掉的a的數目就是1,最中間的a沒有必要刪除,因此答案就是2.注意對於新串長度為奇數的情況要枚舉中間的位置。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#define ll long long
#define pb push_back
using namespace std;
int sum1[100005], sum2[100005];
int p[1000005];
int main() {
int T;
cin >> T;
//T = 1;
while(T--) {
int n;
cin >> n;
string s;
cin >> s;
int ans = 0x3f3f3f3f;
for(int i = 0; i < 26; i++) {
string s1 = "";
sum1[0] = sum2[n + 1] = sum2[n] = 0;
char now = 'a' + i;
for(int j = 0; j < s.size(); j++) {
if(s[j] == now) {
if(j == 0) sum1[j] = 1;
else sum1[j] = sum1[j - 1] + 1;
} else {
if(j == 0) sum1[j] = 0;
else sum1[j] = sum1[j - 1];
s1 += s[j];
p[s1.size() - 1] = j;
}
}
for(int j = s.size() - 1; j >= 0; j--) {
sum2[j] = sum2[j + 1];
if(s[j] == now) sum2[j]++;
}
string s2 = s1;
reverse(s2.begin(), s2.end());
if(s1 == s2) {
int del = 0;
for(int k = 0; k < s1.size() / 2 + (s1.size() & 1 ? 1 : 0); k++) {
int pos1 = p[k], pos2 = p[s1.size() - 1 - k];
if(k == 0) del += abs(sum1[pos1] - sum2[pos2]);
else del += abs((sum1[pos1] - sum1[p[k - 1]]) - (sum2[pos2] - sum2[p[s1.size() - k]]));
}
ans = min(ans, del);
}
}
if(ans == 0x3f3f3f3f) cout << -1 << endl;
else cout << ans << endl;
}
return 0;
}
// 1
// 8
// rprarlap
D. Vupsen, Pupsen and 0
首先對於n為偶數的情況很好辦,直接相鄰兩個消掉即可。對於n是奇數的情況可以這么做:前面n - 3個數同樣兩兩抵消,后三個數設為a, b, c。那么可以把b和c看作一個數b+c,這樣就變成兩個數的情況:a, b+c,構造出來的新數列應該是b+c, -a,把-a分配給最后兩個數(考慮乘法分配律),最終后三個數就是a, b, c對應b+c, -a, -a。但是這樣有一個問題:如果b+c=0,最后構造出來的數列就會有0,不符合題意。此時仔細想一下就會發現,a, b, c三個數不可能兩兩相加都為0(因為保證輸入數列不含0),我們可以找相加不為0的兩個數組合即可。
#include <iostream>
#define INF 0x3f3f3f3f3f
#define eps 1e-6
#define PI acos(-1.0)
#define pb push_back
#define eif else if
#define en putchar('\n')
#define rep(i, x, y) for (int i = x; i < y; i++)
#define red(i, x, y) for (int i = x; i > y; i--)
#define mem(a, x) memset(a, x, sizeof(a))
#define IOS cin.tie(0), ios::sync_with_stdio(false)
#define maxn 100005
#define co(x) cout << x << " ";
typedef long long ll;
#define int long long
#define pll pair<ll, ll>
using namespace std;
ll a[maxn], b[maxn];
ll gcd(ll a, ll b) {
return b ? gcd(b, a % b) : a;
}
void solve() {
int n;
cin >> n;
rep(i, 1, n + 1) {
cin >> a[i];
}
if(n & 1) {
for(int i = 1; i < n - 2; i += 2) {
if(a[i] > 0 && a[i + 1] > 0) {
b[i] = -a[i + 1], b[i + 1] = a[i];
} else if(a[i] < 0 && a[i + 1] < 0) {
b[i] = -a[i + 1], b[i + 1] = a[i];
} else if(a[i] > 0 && a[i + 1] < 0) {
b[i] = -a[i + 1], b[i + 1] = a[i];
} else {
b[i] = a[i + 1], b[i + 1] = -a[i];
}
}
//n - 2 n - 1 n
int tmp = a[n - 1] + a[n];
if(tmp != 0) {
if(a[n - 2] > 0 && tmp > 0) {
b[n - 2] = -tmp, b[n - 1] = b[n] = a[n - 2];
} else if(a[n - 2] < 0 && tmp < 0) {
b[n - 2] = -tmp, b[n - 1] = b[n] = a[n - 2];
} else if(a[n - 2] > 0 && tmp < 0) {
b[n - 2] = -tmp, b[n - 1] = b[n] = a[n - 2];
} else {
b[n - 2] = tmp, b[n - 1] = b[n] = -a[n - 2];
}
} else if(a[n - 2] + a[n] != 0) {
int tmp = a[n - 2] + a[n];
if(a[n - 1] > 0 && tmp > 0) {
b[n - 1] = -tmp, b[n - 2] = b[n] = a[n - 1];
} else if(a[n - 2] < 0 && tmp < 0) {
b[n - 1] = -tmp, b[n - 2] = b[n] = a[n - 1];
} else if(a[n - 2] > 0 && tmp < 0) {
b[n - 1] = -tmp, b[n - 2] = b[n] = a[n - 1];
} else {
b[n - 1] = tmp, b[n - 2] = b[n] = -a[n - 1];
}
} else {
int tmp = a[n - 2] + a[n - 1];
if(a[n] > 0 && tmp > 0) {
b[n] = -tmp, b[n - 2] = b[n - 1] = a[n];
} else if(a[n - 2] < 0 && tmp < 0) {
b[n] = -tmp, b[n - 2] = b[n - 1] = a[n];
} else if(a[n - 2] > 0 && tmp < 0) {
b[n] = -tmp, b[n - 2] = b[n - 1] = a[n];
} else {
b[n] = tmp, b[n - 2] = b[n - 1] = -a[n];
}
}
for(int i = 1; i <= n; i++) cout << b[i] << " ";
cout << endl;
}
else {
for(int i = 1; i < n; i += 2) {
if(a[i] > 0 && a[i + 1] > 0) {
b[i] = -a[i + 1], b[i + 1] = a[i];
} else if(a[i] < 0 && a[i + 1] < 0) {
b[i] = -a[i + 1], b[i + 1] = a[i];
} else if(a[i] > 0 && a[i + 1] < 0) {
b[i] = -a[i + 1], b[i + 1] = a[i];
} else {
b[i] = a[i + 1], b[i + 1] = -a[i];
}
}
for(int i = 1; i <= n; i++) cout << b[i] << " ";
cout << endl;
}
}
signed main()
{
int T = 1;
cin >> T;
while (T--)
{
solve();
}
}
F1. Korney Korneevich and XOR (easy version)
比賽的時候思路有點偏沒做出來....賽后看了一眼大佬代碼發現還是挺簡單的...
暴力思路就是遍歷的時候不斷找遞增子序列,把得到的答案插進set。考慮優化。注意到值域實際上只有500,可以直接用一個桶來維護每個答案的構成序列的最末尾的那個數(貪心地讓其盡可能小,這樣才能使能更新到的值盡可能多),這樣就可以很方便地更新了。
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
int n, a[100005], b[1005];
int main() {
cin >> n;
memset(b, 0x3f3f3f3f, sizeof(b));
for(int i = 1; i <= n; i++) {
cin >> a[i];
}
for(int i = 1; i <= n; i++) {
b[a[i]] = min(b[a[i]], a[i]);//自己肯定能湊出來
for(int j = 0; j <= 512; j++) {
if(b[j] <= a[i]) b[j ^ a[i]] = min(b[j ^ a[i]], a[i]);//盡可能讓最后一個數小
}
}
vector<int> ans;
for(int i = 0; i <= 512; i++) {
if(b[i] != 0x3f3f3f3f) {//如果這個值能有對應的子序列
ans.push_back(i);
}
}
cout << ans.size() << endl;
for(auto x : ans) {
cout << x << " ";
}
return 0;
}
