Codeforces Round #750 (Div. 2) ABCDF1
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;
}