版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
A - Yellow Cards
分析:分k1和k2的大小情况讨论一下就可以了。
#include "bits/stdc++.h"
using namespace std;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 4;
struct BIT {
int n;vector<int> v;
BIT(int n) : n(n) { v.resize(n + 1); }
void update(long long x, long long d) { while (x <= n) { v[x] += d;/*if (v[x] >= mod)v[x] -= mod*/;x += (x & -x); }}
long long que(long long x) { long long res = 0;while (x > 0) { res += v[x];/*if (res >= mod)res -= mod*/;x -= (x & -x); }return res; }
};
long long qk(long long a, long long n) {
long long res = 1;
while (n) {
if (n & 1)res = res * a % mod;
n >>= 1;
a = a * a % mod;
}
return res;
}
int a[maxn];
int main() {
int a1,a2;
int k1,k2;
int n;
cin>>a1>>a2>>k1>>k2>>n;
int temp = a1*(k1-1) + a2*(k2-1);
int mini = min(n - temp,a1+a2);
int maxi = 0;
if(mini <0)mini = 0;
if(k1<k2){
for (int i = 1; i <= a1; ++i) {
if(n >= k1){
maxi ++;
n-=k1;
}
}
for (int i = 1; i <= a2; ++i) {
if(n >= k2){
maxi ++;
n-=k2;
}
}
}
else {
for (int i = 1; i <= a2; ++i) {
if(n >= k2){
maxi ++;
n-=k2;
}
}
for (int i = 1; i <= a1; ++i) {
if(n >= k1){
maxi ++;
n-=k1;
}
}
}
printf("%d %d\n",mini,maxi);
}
B - The Number of Products
分析:枚举左端点,用函数f(l)表示以l为左端点且满足条件的区间的个数。那么记录一下正数和负数的个数,z,f,如果第i个是正数,那么z--,否则f--,再swap(z,f)就可以了。
#include "bits/stdc++.h"
using namespace std;
const int mod = 1e9 + 7;
const int maxn = 2e5 + 4;
struct BIT {
int n;vector<int> v;
BIT(int n) : n(n) { v.resize(n + 1); }
void update(long long x, long long d) { while (x <= n) { v[x] += d;/*if (v[x] >= mod)v[x] -= mod*/;x += (x & -x); }}
long long que(long long x) { long long res = 0;while (x > 0) { res += v[x];/*if (res >= mod)res -= mod*/;x -= (x & -x); }return res; }
};
long long qk(long long a, long long n) {
long long res = 1;
while (n) {
if (n & 1)res = res * a % mod;
n >>= 1;
a = a * a % mod;
}
return res;
}
int a[maxn];
int main() {
int n;
cin>>n;
for (int i = 1; i <= n; ++i) {
scanf("%d",&a[i]);
if(a[i]<0)a[i]=-1;
else a[i]=1;
}
int z = 0,f = 0;
int sum = 1;
for (int i = 1; i <= n; ++i) {
sum*=a[i];
if(sum > 0)z ++;
else f++;
}
long long ans = 0;
for (int i = 1; i <= n; ++i) {
ans += z;
if(a[i] > 0){
z--;
}
else {
f--;
swap(z,f);
}
}
printf("%lld %lld\n",1LL*n*(n+1)/2 - ans,ans);
}
C - Swap Letters
分析:将a和b不同的地方记为一对pair,那么可能出现ab,ba两种情况。ab和ab可以通过一次操作完成,ba和ba也同理,ab和ba需要额外的一次操作,然后直接算一下就可以了。
#include "bits/stdc++.h"
using namespace std;
const int mod = 1e9 + 7;
const int maxn = 2e5 + 4;
struct BIT {
int n;vector<int> v;
BIT(int n) : n(n) { v.resize(n + 1); }
void update(long long x, long long d) { while (x <= n) { v[x] += d;/*if (v[x] >= mod)v[x] -= mod*/;x += (x & -x); }}
long long que(long long x) { long long res = 0;while (x > 0) { res += v[x];/*if (res >= mod)res -= mod*/;x -= (x & -x); }return res; }
};
long long qk(long long a, long long n) {
long long res = 1;
while (n) {
if (n & 1)res = res * a % mod;
n >>= 1;
a = a * a % mod;
}
return res;
}
int main() {
string s,t;
int n;
cin>>n>>s>>t;
vector<int>v1,v2;
for (int i = 0; i < n; ++i) {
if(s[i]==t[i])continue;
else {
if(s[i] == 'a')v1.push_back(1+i);
else v2.push_back(1+i);
}
}
if((int)(v1.size()+v2.size()) % 2 == 0){
vector<pair<int,int>>ans;
for (int i = 1; i < v1.size(); i+=2) {
ans.push_back(make_pair(v1[i],v1[i-1]));
}
for (int i = 1; i < v2.size(); i+=2) {
ans.push_back(make_pair(v2[i],v2[i-1]));
}
if(v1.size()&1){
int pos1 = v1.size()-1,pos2 = v2.size()-1;
ans.push_back(make_pair(v1[pos1],v1[pos1]));
ans.push_back(make_pair(v1[pos1],v2[pos2]));
}
printf("%d\n",ans.size());
for (int i = 0; i < ans.size(); ++i) {
printf("%d %d\n",ans[i].first,ans[i].second);
}
}
else puts("-1");
}
D - Ticket Game
分析:首先将问题抽象一下,将左边的数的和记为suml,右边的数的和记为sumr,左边的问号记为lt,右边的记为rt。
那么问题变为,最开始sum为sumr-suml。两个人轮流操作,每个人每次可以选择一种操作,减少0到9(最多lt次),或者增加0到9(最多rt次)。第一个人想让sum最后不等于0,第二个人想让最后等于0。
然后枚举一下几种情况就可以了。
最后可以发现,有效操作数可等效于rt与lt的差值,当(lt-rt)/2*9==sum的时候才有后手必胜。
#include "bits/stdc++.h"
using namespace std;
const int mod = 1e9 + 7;
const int maxn = 2e5 + 4;
struct BIT {
int n;vector<int> v;
BIT(int n) : n(n) { v.resize(n + 1); }
void update(long long x, long long d) { while (x <= n) { v[x] += d;/*if (v[x] >= mod)v[x] -= mod*/;x += (x & -x); }}
long long que(long long x) { long long res = 0;while (x > 0) { res += v[x];/*if (res >= mod)res -= mod*/;x -= (x & -x); }return res; }
};
long long qk(long long a, long long n) {
long long res = 1;
while (n) {
if (n & 1)res = res * a % mod;
n >>= 1;
a = a * a % mod;
}
return res;
}
int main() {
int n;
string s;
cin>>n>>s;
int lsum,lt,rsum,rt;
lsum = lt = rsum = rt = 0;
for (int i = 0; i < n/2; ++i) {
if(s[i]=='?')lt++;
else lsum += s[i]-'0';
}
for (int i = n/2; i < n; ++i) {
if(s[i]=='?')rt++;
else rsum += s[i]-'0';
}
int sum = rsum - lsum;
bool ok;
int temp = lt - rt;
if(temp & 1)ok = 1;
else {
if(temp / 2 * 9 == sum)ok = 0;
else ok = 1;
}
if(ok)puts("Monocarp");
else puts("Bicarp");
}
E - Marbles
分析:用cost[i][j]表示,在只考虑ij两种颜色的情况下,把i全部移到j的前面的最小花费。这个只需要跑一遍就可以得到。
用dp[sta]表示在sta状态下(即只考虑sta中存在的几种颜色),使每种颜色各自独立所需的最小花费,那么枚举一下最后一次移动哪个颜色,记忆化跑一下就可以了。
#include "bits/stdc++.h"
using namespace std;
long long cost[22][22];
int a[400004];
long long dp[1 << 22];
long long dfs(int sta) {
if (sta == 0)return 0;
if (dp[sta] != -1)return dp[sta];
long long ans = 1e18;
for (int i = 1; i <= 20; ++i) {
int temp = 1 << i;
if (!(temp & sta))continue;
int nxt = sta ^temp;
long long sum = dfs(nxt);
for (int j = 1; j <= 20; ++j) {
int tem = (1 << j);
if (tem & nxt)sum += cost[i][j];
}
ans = min(ans, sum);
}
return dp[sta] = ans;
}
int main() {
memset(dp, -1, sizeof(dp));
memset(cost, 0, sizeof(cost));
int n;
cin >> n;
int num[22] = {0};
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
num[a[i]]++;
for (int j = 1; j <= 20; ++j) {
if (j == a[i])continue;
cost[a[i]][j] += num[j];
}
}
cout << dfs((1 << 21) - 2) << endl;
}