【AtCoder】AGC026 题解
A - Colorful Slimes 2
找相同颜色的一段,然后答案加上段长除2下取整
代码
#include <iostream>
#include <cstdio>
using namespace std;
int N;
int a[105];
int main() {
scanf("%d",&N);
for(int i = 1 ; i <= N ; ++i) {
scanf("%d",&a[i]);
}
int ans = 0;
int cnt = 0;
for(int i = 1 ; i <= N ; ++i) {
if(a[i] != a[i - 1]) {
ans += cnt / 2;
cnt = 0;
}
++cnt;
}
ans += cnt / 2;
printf("%d\n",ans);
}
B - rng_10s
题解
如果A < B一定不可以
如果C>=B并且D>=B显然一定可以
如果D < B那么一定不可以
然后如果A大于C,那么就买几个B使得A减到C以下,如果减的过程中买不到了,那么就不可以
每次买完还需要补货的时候相当于从A开始,每次加上B和D的gcd,如果这个值落在了C和B之间,那么就不合法了
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
//#define ivorysi
#define fi first
#define se second
#define MAXN 25005
#define enter putchar('\n')
#define space putchar(' ')
typedef long long int64;
using namespace std;
template <class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
c = getchar();
if(c == '-') f = -1;
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template <class T>
void out(T x) {
if(x < 0) {x = -x;}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
int T;
int64 A,B,C,D;
int64 gcd(int64 a,int64 b) {
return b == 0 ? a : gcd(b,a % b);
}
void Solve() {
read(A);read(B);read(C);read(D);
if(A < B) {puts("No");}
else {
if(C >= B && D >= B) puts("Yes");
else if(D < B) puts("No");
else {
if(A > C) {
int64 t = (A - C - 1) / B + 1;
if(t > A / B) {
puts("No");return;
}
A -= B * t;
}
int64 g = gcd(D % B,B);
if((C + 1 - A - 1) / g + 1 == (B - A - 1) / g + 1) puts("Yes");
else puts("No");
}
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
read(T);
while(T--) {
Solve();
}
}
C - String Coloring
题解
直接折半搜索即可
用哈希表维护前半部分拆分方式的两个字符串的哈希值
再枚举后一半的拆分方式查哈希表即可
代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define enter putchar('\n')
#define space putchar(' ')
#define fi first
#define se second
#define ba 47
#define mo 999999137
#define mod 974711
//#define ivorysi
#define pii pair<int,int>
using namespace std;
typedef long long int64;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {putchar('-');x = -x;}
if(x >= 10) out(x / 10);
putchar('0' + x % 10);
}
struct Hash {
char t[20];
int64 val;
int len;
friend bool operator < (const Hash &a,const Hash &b) {
return a.val < b.val;
}
friend bool operator == (const Hash &a,const Hash &b) {
if(a.val != b.val) return false;
if(a.len != b.len) return false;
for(int i = 1 ; i <= a.len ; ++i) {
if(a.t[i] != b.t[i]) return false;
}
return true;
}
}B[1000005];
int cnt;
int64 e[55];
struct Mmp {
struct node {
int next,v;
int64 x;
}E[1000005];
int head[mod + 5],sumE;
void clear() {
memset(head,0,sizeof(head));
sumE = 0;
}
void add(int64 x,int v) {
int u = x % mod;
E[++sumE].x = x;
E[sumE].v = v;
E[sumE].next = head[u];
head[u] = sumE;
}
void Insert(int64 x) {
int u = x % mod;
for(int i = head[u] ; i ; i = E[i].next) {
if(E[i].x == x) {E[i].v++;return;}
}
add(x,1);
}
int Query(int64 x) {
int u = x % mod;
for(int i = head[u]; i ; i = E[i].next) {
if(E[i].x == x) return E[i].v;
}
return 0;
}
}M1,M2;
int64 Calc(char *s,int l) {
int64 res = 0;
for(int i = 1 ; i <= l ; ++i) {
res += (s[i] - 'a' + 1) * e[i] % mo;
res %= mo;
}
return res;
}
void Insert(char *s,int l) {
++cnt;
for(int i = 1 ; i <= l ; ++i) B[cnt].t[i] = s[i];
B[cnt].len = l;B[cnt].val = Calc(s,l);
}
int N;
char s[55];
void Solve() {
read(N);
e[0] = 1;
for(int i = 1 ; i <= N ; ++i) e[i] = e[i - 1] * ba % mo;
scanf("%s",s + 1);
char t1[25],t2[25];
int c1,c2;
for(int S = 0 ; S < (1 << N) ; ++S) {
c1 = c2 = 0;
int T = 0;
for(int i = 1 ; i <= N ; ++i) {
if(S >> (i - 1) & 1) t1[++c1] = s[i];
else {t2[++c2] = s[i];T |= (1 << i - 1);}
}
if(S > T) continue;
if(c1) Insert(t1,c1);
if(c2) Insert(t2,c2);
}
sort(B + 1,B + cnt + 1);
cnt = unique(B + 1,B + cnt + 1) - B - 1;
M1.clear();M2.clear();
for(int i = 1 ; i <= cnt ; ++i) {
M1.add(B[i].val,i);
}
for(int S = 0 ; S < (1 << N) ; ++S) {
c1 = c2 = 0;
for(int i = 1 ; i <= N ; ++i) {
if(S >> (i - 1) & 1) t1[++c1] = s[i];
else {t2[++c2] = s[i];}
}
int d1 = 0,d2 = 0;
if(c1) d1 = M1.Query(Calc(t1,c1));
if(c2) d2 = M1.Query(Calc(t2,c2));
M2.Insert(1LL * d1 * (cnt + 1) + d2);
}
int64 ans = 0;
for(int S = 0 ; S < (1 << N) ; ++S) {
c1 = c2 = 0;
for(int i = N + 1 ; i <= 2 * N ; ++i) {
if(S >> (i - N - 1) & 1) t1[++c1] = s[i];
else {t2[++c2] = s[i];}
}
reverse(t1 + 1,t1 + c1 + 1);
reverse(t2 + 1,t2 + c2 + 1);
int d1 = 0,d2 = 0;
if(c1) d1 = M1.Query(Calc(t1,c1));
if(c2) d2 = M1.Query(Calc(t2,c2));
ans += M2.Query(1LL * d1 * (cnt + 1) + d2);
}
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
}
D - Histogram Coloring
题解
我们考虑从上往下,对于每个分离的直方图的横列进行dp,然后再把他们合起来
我们发现,如果直方图不是10101010或0101010101的形式,那么以下所有列就只有一种放置方法
那么我们记录两个值,一个是直方图最下面一行填的是1010101或01010101,记为dp[S][1],一个是所有的方案数记为dp[S][2]
转移方法是对于一个列数一样的矩形块
dp[S][1]是它上面所有的直方图dp[S][1]乘起来,然后再乘上2的行数次幂
dp[S][2]我们认为是如果是010101或101010,那么下面对应的有两种方式,剩下的只有一种,其余的方块随便填,下面每一行是上一行取反
是上面所有直方图的(dp[T][1] + dp[T][2])乘起来,然后再乘上2的剩余方块数的幂
但是dp[S][2]也应该包括相邻两行有相同的情况,我们就再加上dp[S][1],同时减掉dp[S][1]中我们每行都不同的情况
代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define enter putchar('\n')
#define space putchar(' ')
#define fi first
#define se second
#define mp make_pair
#define ba 47
#define mo 999999137
#define mod 974711
//#define ivorysi
#define pii pair<int,int>
using namespace std;
typedef long long int64;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {putchar('-');x = -x;}
if(x >= 10) out(x / 10);
putchar('0' + x % 10);
}
const int MOD = 1000000007;
int N;
int h[105];
bool vis[105];
int inc(int a,int b) {
return a + b >= MOD ? a + b - MOD : a + b;
}
int mul(int a,int b) {
return 1LL * a * b % MOD;
}
int fpow(int x,int c) {
int res = 1,t = x;
while(c) {
if(c & 1) res = mul(res,t);
t = mul(t,t);
c >>= 1;
}
return res;
}
void update(int &x,int y) {
x = inc(x,y);
}
pii Solve(int l,int r,int v) {
int minv = 1e9;
for(int i = l ; i <= r ; ++i) minv = min(minv,h[i]);
int p,cnt = 0;
pii res = mp(1,1);
for(int i = l ; i <= r ; ++i) {
if(h[i] > minv) ++cnt;
}
for(int i = l ; i <= r ; ++i) {
if(h[i] > minv) {
p = i;
while(p < r && h[p + 1] > minv) ++p;
pii f = Solve(i,p,minv);
res.fi = mul(res.fi,f.fi);
res.se = mul(res.se,inc(f.se,f.fi));
i = p;
}
}
int t = mul(res.fi,2);
res.se = mul(res.se,fpow(2,r - l + 1 - cnt));
res.fi = mul(res.fi,fpow(2,minv - v));
res.se = inc(res.se,inc(res.fi,MOD - t));
return res;
}
void Solve() {
read(N);
for(int i = 1 ; i <= N ; ++i) {read(h[i]);}
pii ans = Solve(1,N,0);
out(ans.se);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
}
E - Synchronized Subsequence
题解
如果b在a前就一直选,选到某个最大的a的位置会更改成一段a在b前
如果这个a在b前是最后一部分就取到所有的abababab...前,否则就跳过这一段
具体就用string维护一下后缀能取到的max字符串就好了
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <ctime>
#include <map>
#include <set>
#define fi first
#define se second
#define pii pair<int,int>
//#define ivorysi
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 6005
using namespace std;
typedef long long int64;
typedef double db;
typedef unsigned int u32;
template<class T>
void read(T &res) {
res = 0;T f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9' ) {
res = res * 10 - '0' + c;
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
namespace task {
char s[MAXN];
int N,a[MAXN],b[MAXN],tota,totb,pos[MAXN];
string str[MAXN];
bool vis[MAXN];
void Init() {
read(N);
scanf("%s",s + 1);
tota = 0;totb = 0;
for(int i = 1 ; i <= 2 * N ; ++i) {
if(s[i] == 'a') {a[++tota] = i;pos[i] = tota;}
else {b[++totb] = i;pos[i] = totb;}
}
}
void Solve() {
str[2 * N + 1] = "";
for(int i = 2 * N ; i >= 1 ; --i) {
str[i] = max(str[i],str[i + 1]);
string t = "";
int p = pos[i];
if(s[i] == 'a' && a[p] < b[p]) {
str[i] = max(str[i],"ab" + str[b[p] + 1]);
}
else if(s[i] == 'b' && b[p] < a[p]) {
memset(vis,0,sizeof(vis));
int maxv = a[p];
for(int j = i ; j <= maxv ; ++j) {
if(s[j] == 'b') {
p = pos[j];
vis[b[p]] = 1;vis[a[p]] = 1;
maxv = max(a[p],maxv);
}
if(vis[j]) t += s[j];
}
t += str[maxv + 1];
str[i] = max(str[i],t);
}
}
cout<<str[1]<<endl;
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
task::Init();
task::Solve();
return 0;
}
F - Manju Game
题解
我们把整个序列黑白染色变成
BWBWBWBW的形式
如果是偶数的话
先手可以保证自己得到全部的B或全部的W
后手可以在先手做出选择后,保证自己得到另一种颜色的所有
这样的话,相当于先手得到黑白颜色中较多的那个,后手得到较少的那个
如果是奇数的话
先手还是可以保证自己得到所有B
那么先手选W的话解会不会更优
先手在选B之后,便不可能再选W,如果某一次B进行完了以后先手选了W结果更优,后手可以撤销上一次操作,使得先后手所拿到的物品相反,结果更劣
先手假如可以选\(W_1,W_2,W_3...W_k\)如果,我们能取的区间如果全取B的话,这个区间的B - W是最小的,所以我们限定一下这个区间B - W的最小值,二分一下,然后用一个dp判断即可
代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define enter putchar('\n')
#define space putchar(' ')
#define fi first
#define se second
#define mp make_pair
//#define ivorysi
#define pii pair<int,int>
using namespace std;
typedef long long int64;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {putchar('-');x = -x;}
if(x >= 10) out(x / 10);
putchar('0' + x % 10);
}
int N;
int64 a[300005],sum[300005][2];
bool check(int64 mid) {
int64 t = 0;
for(int i = 2 ; i <= N ; i += 2) {
if(sum[i - 1][1] - sum[i - 1][0] + t >= mid) {
t = max(sum[i][0] - sum[i][1],t);
}
}
if(sum[N][1] - sum[N][0] + t >= mid) return true;
return false;
}
void Solve() {
read(N);
for(int i = 1 ; i <= N ; ++i) read(a[i]);
int64 L = 0,R = 0;
for(int i = 1 ; i <= N ; ++i) {
R += a[i];L -= a[i];
sum[i][0] = sum[i - 1][0];
sum[i][1] = sum[i - 1][1];
sum[i][i & 1] += a[i];
}
if(N % 2 == 0) {
out(max(sum[N][0],sum[N][1]));space;out(min(sum[N][0],sum[N][1]));enter;
return;
}
while(L < R) {
int64 mid = (L + R + 1) >> 1;
if(check(mid)) L = mid;
else R = mid - 1;
}
int64 a = L + sum[N][0];
int64 b = sum[N][0] + sum[N][1] - a;
out(a);space;out(b);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
}