AGC006
A - Prefix and Suffix
……
#include#define fi first#define se second#define pii pair #define mp make_pair#define pb push_back#define space putchar(' ')#define enter putchar('\n')#define eps 1e-10#define MAXN 300005//#define ivorysiusing namespace std;typedef long long int64;typedef unsigned int u32;typedef double db;template 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 +c - '0'; c = getchar(); } res *= f;}template void out(T x) { if(x < 0) {x = -x;putchar('-');} if(x >= 10) { out(x / 10); } putchar('0' + x % 10);}int N;string s,t;void Solve() { read(N); cin >> s >> t; for(int i = N ; i >= 1 ; --i) { if(s.substr(N - i,i) == t.substr(0,i)) { out(2 * N - i);enter;return; } } out(2 * N);enter;}int main() {#ifdef ivorysi freopen("f1.in","r",stdin);#endif Solve(); return 0;}
B - Median Pyramid Easy
发现如果中间有两个目标的x那么之后这两个x可以互相扶持一直到顶(事实上这也是D做题的关键)
如何造出来呢,如果x至少有一个比它小的和比它大的
我们可以中间填-1 0 1其中0在正中间,表示x,1表示一个比x大的数,-1表示一个比x小的数
如果还有比0小的,放在1的后面,有比0大的放在-1的前面,就可以让中间两个0了
剩下的随便放就好了
#include#define fi first#define se second#define pii pair #define mp make_pair#define pb push_back#define space putchar(' ')#define enter putchar('\n')#define eps 1e-10#define MAXN 100005//#define ivorysiusing namespace std;typedef long long int64;typedef unsigned int u32;typedef double db;template 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 +c - '0'; c = getchar(); } res *= f;}template void out(T x) { if(x < 0) {x = -x;putchar('-');} if(x >= 10) { out(x / 10); } putchar('0' + x % 10);}int N,x;int a[MAXN];vector l,r;deque q;void Solve() { read(N);read(x); if(x == 1 || x == 2 * N - 1) {puts("No");return;} puts("Yes"); for(int i = 1 ; i < x ; ++i) l.pb(i); for(int i = x + 1 ; i <= 2 * N - 1 ; ++i) r.pb(i); q.pb(x); bool f = 0; while(l.size() && r.size()) { if(f) { q.push_back(l.back()); q.push_front(r.back()); } else { q.push_back(r.back()); q.push_front(l.back()); } l.pop_back();r.pop_back(); f ^= 1; } if(r.size() > l.size()) swap(l,r); while(l.size()) { q.push_back(l.back()); l.pop_back(); q.push_front(l.back()); l.pop_back(); } for(int i = 0 ; i < 2 * N - 1 ; ++i) {out(q[i]);space;} enter;}int main() {#ifdef ivorysi freopen("f1.in","r",stdin);#endif Solve(); return 0;}
C - Rabbit Exercise
如果对\(x_{2}\)进行操作
那么就变成
\(x_{1},x_{3} + x_{1} - x_{2},x_{3}\)
这个需要一点想象力,觉得这种变换总需要有个不变量,或者实现了某种交换
发现交换的是2两边的差分,于是问题就可以转化成一个映射的K次幂,最后把差分归位就可以恢复出最终序列了
#include#define fi first#define se second#define pii pair #define mp make_pair#define pb push_back#define space putchar(' ')#define enter putchar('\n')#define eps 1e-10#define MAXN 100005//#define ivorysiusing namespace std;typedef long long int64;typedef unsigned int u32;typedef double db;template 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 +c - '0'; c = getchar(); } res *= f;}template void out(T x) { if(x < 0) {x = -x;putchar('-');} if(x >= 10) { out(x / 10); } putchar('0' + x % 10);}int x[MAXN],M,N,a[MAXN];int64 l[MAXN],K;struct node { int p[MAXN]; friend node operator * (const node &a,const node &b) { node c; for(int i = 1 ; i < N ; ++i) c.p[i] = b.p[a.p[i]]; return c; }}f,ans;node fpow(node x,int64 c) { node res,t = x; for(int i = 1 ; i < N ; ++i) res.p[i] = i; while(c) { if(c & 1) res = res * t; t = t * t; c >>= 1; } return res;}void Solve() { read(N); for(int i = 1 ; i <= N ; ++i) read(x[i]); read(M);read(K); for(int i = 1 ; i < N ; ++i) a[i] = i; int t; for(int i = 1 ; i <= M ; ++i) { read(t); swap(a[t - 1],a[t]); } for(int i = 1 ; i < N ; ++i) f.p[a[i]] = i; ans = fpow(f,K); l[1] = x[1]; for(int i = 1 ; i < N ; ++i) { l[ans.p[i] + 1] = x[i + 1] - x[i]; } for(int i = 1 ; i <= N ; ++i) { l[i] += l[i - 1]; out(l[i]);enter; }}int main() {#ifdef ivorysi freopen("f1.in","r",stdin);#endif Solve(); return 0;}
D - Median Pyramid Hard
我们二分一个x表示答案应该小于等于x,把小于等于x的都标成0,大于x的都标成1
如果从左到右是1010101这样的形式,即不存在相邻两个数值是一样的,那么每次取反看看中间的位置取反\(N - 1\)次是什么就好
如果存在两个相同的
看看哪个相同(11或00)的离中间最近,最后的答案就是它
#include#define fi first#define se second#define pii pair #define mp make_pair#define pb push_back#define space putchar(' ')#define enter putchar('\n')#define eps 1e-10#define MAXN 100005//#define ivorysiusing namespace std;typedef long long int64;typedef unsigned int u32;typedef double db;template 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 +c - '0'; c = getchar(); } res *= f;}template void out(T x) { if(x < 0) {x = -x;putchar('-');} if(x >= 10) { out(x / 10); } putchar('0' + x % 10);}int N,a[MAXN * 2],v[MAXN * 2];bool check(int x) { for(int i = 1 ; i <= 2 * N - 1 ; ++i) { v[i] = (a[i] > x); } for(int i = 1 ; i < N ; ++i) { if(v[N - i] == v[N - i + 1]) { return v[N - i] != 1; } if(v[N + i] == v[N + i - 1]) { return v[N + i] != 1; } } v[N] ^= ((N - 1) & 1); return v[N] != 1;}void Solve() { read(N); for(int i = 1 ; i <= 2 * N - 1 ; ++i) read(a[i]); int L = 2,R = 2 * N - 2; while(L < R) { int mid = (L + R) >> 1; if(check(mid)) R = mid; else L = mid + 1; } out(L);enter;}int main() {#ifdef ivorysi freopen("f1.in","r",stdin);#endif Solve(); return 0;}
E - Rotate 3x3
发现中间一列怎么动都还在中间的时候,就可以考虑一下是不是和中间位置复原的交换次数有关了
因为交换一次或者当了中间轴一次,上下顺序都会改变,我们就希望交换的次数满足能让这个数上下变成原来样子的奇偶性
因为奇数列和偶数列不交换位置,设\(inv_{e}\)是偶数列彼此交换的位置,\(flip_{e}\)是偶数列初始时需要翻转的位置,同理定义\(inv_{o}\)和\(flip_{o}\)是奇数列的,他们的奇偶性可以确定
当我们交换两个偶数列
\(inv_{e}\)和\(flip_{o}\)同时改变
当我们交换两个奇数列
\(inv_{o}\)和\(flip_{e}\)同时改变
可以发现\(inv_{e}\)和\(flip_o\)奇偶性相等是必要的,\(inv_o\)和\(flip_e\)的奇偶性是相同也是必要的
这也是充分的,我们考虑我们用了所有的\(inv_e\)和所有的\(inv_o\)使得第二行数全部归位,此时\(flip_{o}\)和\(flip_{e}\)都是偶数,我们给出一种构造使得我们能在不交换数原有顺序的情况下翻转两个相邻的奇数列或偶数列
设\(A\)是a列的翻转
初始情况是
\(a,b,c,d,e\)
\(C,B,A,d,e\)
\(C,B,E, D,a\)
\(e,b,c,D,a\)
\(e,b,A,d,C\)
\(a,B,E,d,C\)
\(a,B,c,D,e\)
\(a,d,C,b,e\)
\(c, D,A,b,e\)
\(c,B,a,d,e\)
\(A,b,C,d,e\)
这样就可以证明了
#include#define fi first#define se second#define pii pair #define mp make_pair#define pb push_back#define space putchar(' ')#define enter putchar('\n')#define eps 1e-10#define MAXN 100005//#define ivorysiusing namespace std;typedef long long int64;typedef unsigned int u32;typedef double db;template 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 +c - '0'; c = getchar(); } res *= f;}template void out(T x) { if(x < 0) {x = -x;putchar('-');} if(x >= 10) { out(x / 10); } putchar('0' + x % 10);}int N,a[4][MAXN],inv[2],flip[2];int tr[MAXN * 3];int lowbit(int x) {return x & (-x);}void insert(int x,int v) { while(x <= 3 * N) { tr[x] += v; x += lowbit(x); }}int query(int x) { int r = 0; while(x > 0) { r += tr[x]; x -= lowbit(x); } return r;}void Solve() { read(N); for(int i = 1 ; i <= 3 ; ++i) { for(int j = 1 ; j <= N ; ++j) read(a[i][j]); } for(int i = 1 ; i <= N ; ++i) { if(a[2][i] % 3 != 2) {puts("No");return;} if((a[2][i] / 3 + 1 & 1) != (i & 1)) {puts("No");return;} int b = a[1][i],c = a[3][i]; if(b > c) swap(b,c); if(b != a[2][i] - 1 || c != a[2][i] + 1) {puts("No");return;} if(a[2][i] - 1 == a[3][i]) flip[i & 1] ^= 1; } for(int i = 1 ; i <= N ; i += 2) { inv[i & 1] ^= query(3 * N) - query(a[2][i]) & 1; insert(a[2][i],1); } memset(tr,0,sizeof(tr)); for(int i = 2 ; i <= N ; i += 2) { inv[i & 1] ^= query(3 * N) - query(a[2][i]) & 1; insert(a[2][i],1); } if(flip[0] != inv[1]) {puts("No");return;} if(flip[1] != inv[0]) {puts("No");return;} puts("Yes");}int main() {#ifdef ivorysi freopen("f1.in","r",stdin);#endif Solve(); return 0;}
F - Blackout
一个点\((a,b)\)相当于一条边从\(a\)到\(b\)
\((a,b)\)到\((b,c)\)会得到一条边\((c,a)\)
显然边只会加在一个弱连通的图里,我们对每个弱连通的图分别处理
我们把这张图三色染色,如果是出边则+1否则-1,取模3
如果三色染色可以成功,但是图中三个颜色并不齐,那么这个弱连通图加不了任何边
如果三色染色成功了,三个颜色都齐了,那所有A可以往所有的B连边,所有的B可以往所有的C连边,所有的C可以往所有的A连边
如果三色染色不成功,那这个弱连通图两两之间的点都可以连边,可以有自环
#include#define fi first#define se second#define pii pair #define mp make_pair#define pb push_back#define space putchar(' ')#define enter putchar('\n')#define eps 1e-10#define MAXN 100005//#define ivorysiusing namespace std;typedef long long int64;typedef unsigned int u32;typedef double db;template 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 +c - '0'; c = getchar(); } res *= f;}template void out(T x) { if(x < 0) {x = -x;putchar('-');} if(x >= 10) { out(x / 10); } putchar('0' + x % 10);}int N,M;struct node { int to,v,next;}E[MAXN * 2];int head[MAXN],sumE,col[MAXN];bool vis[MAXN];int cnt[5];int64 ans,s,num;bool flag = 0;void add(int u,int v,int c) { E[++sumE].to = v; E[sumE].next = head[u]; E[sumE].v = c; head[u] = sumE;}void dfs(int u) { vis[u] = 1;++num; ++cnt[col[u]]; for(int i = head[u] ; i ; i= E[i].next) { int v = E[i].to;++s; if(vis[v]) { if(col[v] != (col[u] + E[i].v + 3) % 3) flag = 1; } else { col[v] = (col[u] + E[i].v + 3) % 3; dfs(v); } }}void Solve() { read(N);read(M); int a,b; for(int i = 1 ; i <= M ; ++i) { read(a);read(b); add(a,b,1); add(b,a,-1); } for(int i = 1 ; i <= N ; ++i) { if(!vis[i]) { memset(cnt,0,sizeof(cnt)); col[i] = 0; s = 0;num = 0; flag = 0;dfs(i); if(!flag) { if(!cnt[0] || !cnt[1] || !cnt[2]) { ans += s / 2; } else { ans += 1LL * cnt[1] * cnt[0]; ans += 1LL * cnt[2] * cnt[1]; ans += 1LL * cnt[2] * cnt[0]; } } else { ans += 1LL * num * num; } } } out(ans);enter;}int main() {#ifdef ivorysi freopen("f1.in","r",stdin);#endif Solve(); return 0;