Codeforces Round# 305 (Div 1)
#include <bits/stdc++.h> #define maxn 1000010 using namespace std; typedef long long ll; bool vis[maxn]; int md, h, a, x, y; int Go(int h, int x, int y){ memset(vis, 0, sizeof vis); int cnt = 0; while(true){ if(vis[h]) return -1; vis[h] = 1; h = (1ll * h * x + y) % md; ++ cnt; if(h == a) return cnt; } } int main(){ scanf("%d", &md); scanf("%d%d%d%d", &h, &a, &x, &y); int a1 = Go(h, x, y), b1 = Go(a, x, y); scanf("%d%d%d%d", &h, &a, &x, &y); int a2 = Go(h, x, y), b2 = Go(a, x, y); if(a1 == -1 || a2 == -1)return puts("-1"), 0; if(b1 == -1 && b2 == -1){ if(a1 == a2)printf("%d\n", a1); else printf("-1\n"); return 0; } if(b1 != -1 && b2 != -1){ for(int i = 0; i <= md; i ++){ if(a1 + 1ll * b1 * i >= a2 && (a1 + 1ll * b1 * i - a2) % b2 == 0){ cout << a1 + 1ll * b1 * i << endl; return 0; } }return puts("-1"), 0; } else{ if(b1 == -1)swap(a1, a2), swap(b1, b2); if(a2 >= a1 && (a2 - a1) % b1 == 0) printf("%d\n", a2); else return puts("-1"), 0; } return 0; }
题目大意: 就是给你一个序列,定义f(x)为(所有区间长度为x的最小值)的最大值,输出f(1)....f(n)
n ≤ 2 * 10^5
Sol:感觉用并查集就可以水。。
#include <bits/stdc++.h> #define maxn 200010 using namespace std; int n; int a[maxn]; int fa[maxn]; int getfa(int x){return x == fa[x] ? x : fa[x] = getfa(fa[x]);} int h[maxn]; bool cmp(int i, int j){ if(a[i] == a[j]) return i < j; return a[i] < a[j]; } int t; int size[maxn], f[maxn]; inline void update(int x){ fa[x] = x, size[x] = 1; if(t = getfa(x-1))fa[t] = x, size[x] += size[t]; if(t = getfa(x+1))fa[t] = x, size[x] += size[t]; f[size[x]] = max(f[size[x]], a[x]); return; } int main(){ scanf("%d", &n); for(int i = 1; i <= n; i ++) scanf("%d", &a[i]), h[i] = i; sort(h+1, h+1+n, cmp); for(int i = n; i >= 1; i --) update(h[i]); for(int i = n; i >= 1; i --) f[i] = max(f[i+1], f[i]); for(int i = 1; i <= n; i ++) printf("%d ", f[i]); return 0; }
题目大意:给定一个序列,初始为空,每次从序列中选出一个数字添加或删除,求gcd(Ai, Aj) = 1的有序数对(i, j)的个数。
容斥原理。
#include <bits/stdc++.h> #define maxn 1000010 using namespace std; int N, Q; int A[maxn]; vector<int> P[maxn]; bool vis[maxn]; int p[maxn], primes, mn[maxn]; void prepare(){ mn[1] = 1; int N = 500000; for(int i = 2; i <= N; i ++){ if(!vis[i]){ p[primes ++] = i; mn[i] = i; } for(int j = 0; j < primes; j ++){ if(1ll * i * p[j] > N)break; vis[i * p[j]] = true; if(i % p[j] == 0){mn[i * p[j]] = p[j];break;} mn[i * p[j]] = mn[i]; } } } void FJ(int Id, int A){ while(A != 1){ int now = mn[A]; while(A % now == 0) A /= now; P[Id].push_back(now); } } long long ans; int Bits[100], cnt[maxn]; void update(int Id, int val){ int n = P[Id].size(), S = (1 << n) - 1; for(int i = 0; i <= S; i ++){ long long LCM = 1; for(int j = 0; j < n; j ++) if(i >> j & 1) LCM = LCM * P[Id][j]; cnt[LCM] += val; } } int QAQ(int S, int now){ int n = P[now].size(); long long ret = 0, LCM = 1; for(int i = 0; i < n; i ++) if(S >> i & 1) LCM = LCM * P[now][i]; return cnt[LCM]; } long long work(int now){ int n = P[now].size(); int S = (1 << n) - 1; long long ret = 0; for(int i = 0; i <= S; i ++) if(Bits[i] & 1)ret -= QAQ(i, now); else ret += QAQ(i, now); return ret; } void solve(int Id){ if(vis[Id])update(Id, -1), ans -= work(Id); else ans += work(Id), update(Id, 1); vis[Id] ^= 1; } int main(){ prepare(); for(int i = 1; i < 1<<6; i ++) Bits[i] = __builtin_popcount(i); scanf("%d%d", &N, &Q); for(int i = 1; i <= N; i ++) scanf("%d", &A[i]); for(int i = 1; i <= N; i ++) FJ(i, A[i]); memset(vis, 0, sizeof vis); int Id; for(int i = 1; i <= Q; i ++){ scanf("%d", &Id); solve(Id); printf("%I64d\n", ans); } return 0; }
题目大意:平面上有n个点,你需要给他们一一染色,可以染'b'(blue)或'r'(red),要求每一行和每一列所染色的(红色-蓝色)数目的绝对值<=1,输出染色方案。
n ≤ 2 * 10^5
QAQ虽然说一看就知道是网络流但是数据范围也是吓我一跳QAQ
然而YY半天建图无果。。
首先行和列示要看成点的,给的每一个点(x, y)看成一条边无疑,容量为1
然后广告犇提出了限流思想:既然每行或每列不能相差超过1,那么就可以从源点->每一行连接容量为(cntx[i] / 2)的边,这样红蓝就一定符合条件了!(其中cntx[i]表示第i行有多少个点),从每一列连向汇点同理QAQ
但是这样输出的方案可能还不够,有一些点仍然没有确定怎么办?(假如某一行某一列的点的个数为奇数。。)
然后就弃疗了
orz了一下神犇的题解(虽然说并不知道神犇是谁,但是网络流竟然可以过QAQ)
先把行列离散化一下QAQ,然后如上建边,然后跑一边最大流,然后如果有多出来的就再添加一条容量为1的边,再跑一遍最大流。最后如果割掉了(edge[i<<1])说明此点和S相连,否则和T相连。
某犇:我快YY出正解了
主要程序:(网络流就不写了QAQ)
int main(){ scanf("%d", &n); for(int i = 1; i <= n; i ++) scanf("%d%d", &x[i], &y[i]); for(int i = 1; i <= n; i ++) ++ cx[x[i]], ++ cy[y[i]]; int id = 0; for(int i = 1; i <= 200000; i ++) if(cx[i])Idx[i] = ++ id; for(int i = 1; i <= 200000; i ++) if(cy[i])Idy[i] = ++ id; T = id + 1; for(int i = 1; i <= n; i ++) add(Idx[x[i]], Idy[y[i]], 1); for(int i = 1; i <= 200000; i ++) if(cx[i] > 1) add(S, Idx[i], cx[i] >> 1); for(int i = 1; i <= 200000; i ++) if(cy[i] > 1) add(Idy[i], T, cy[i] >> 1); Dinic(); for(int i = 1; i <= 200000; i ++) if(cx[i] & 1) add(S, Idx[i], 1); for(int i = 1; i <= 200000; i ++) if(cy[i] & 1) add(Idy[i], T, 1); Dinic(); for(int i = 1; i <= n; i ++) if(!edge[i<<1].w) putchar('b'); else putchar('r'); puts(""); return 0; }
给出一大堆字符串,每次询问第k个串在第l~r的串中作为子串出现了多少次
简述:AC自动机(failtree)的dfs序做可持久化。
#include <bits/stdc++.h> #define maxn 200010 using namespace std; int n, m; char str[maxn]; int tr[maxn][26], root, smz; int pos[maxn]; struct Edge{ int to, nxt; }edge[maxn]; int h[maxn], cnt; void add(int u, int v){ cnt ++; edge[cnt].to = v; edge[cnt].nxt = h[u]; h[u] = cnt; } void init(){ memset(tr, -1, sizeof tr); root = smz = 0; } void Insert(int Id){ int N = strlen(str+1), now = root; for(int i = 1; i <= N; i ++){ int c = str[i] - 'a'; if(tr[now][c] == -1)tr[now][c] = ++ smz; now = tr[now][c]; } pos[Id] = now; } queue<int> Q; int fa[maxn], fail[maxn]; void buildfail(){ for(int i = 0; i < 26; i ++) if(tr[root][i] == -1) tr[root][i] = root; else fail[tr[root][i]] = root, Q.push(tr[root][i]), fa[tr[root][i]] = root; while(!Q.empty()){ int u = Q.front(); Q.pop(); for(int i = 0; i < 26; i ++){ if(tr[u][i] == -1)tr[u][i] = tr[fail[u]][i]; else fail[tr[u][i]] = tr[fail[u]][i], Q.push(tr[u][i]), fa[tr[u][i]] = u; } } for(int i = 1; i <= smz; i ++) add(fail[i], i); } int In[maxn], Out[maxn], dfs_clock; void dfs(int u){ In[u] = ++ dfs_clock; for(int i = h[u]; i; i = edge[i].nxt) dfs(edge[i].to); Out[u] = dfs_clock; } #define M 10000010 int T[maxn], L[M], R[M], val[M]; int size; int build(int l, int r){ if(l > r) return 0; int now = ++ size; int mid = l + r >> 1; L[now] = build(l, mid - 1); R[now] = build(mid + 1, r); return now; } int update(int rt, int pos, int l, int r){ int mid = l + r >> 1, now = ++ size; L[now] = L[rt], R[now] = R[rt], val[now] = val[rt] + 1; if(l == r) return now; if(pos <= mid)L[now] = update(L[rt], pos, l, mid); else R[now] = update(R[rt], pos, mid + 1, r); return now; } int ask(int rt, int al, int ar, int l, int r){ if(al == l && ar == r)return val[rt]; int mid = l + r >> 1; if(ar <= mid)return ask(L[rt], al, ar, l, mid); if(al > mid) return ask(R[rt], al, ar, mid + 1, r); return ask(L[rt], al, mid, l, mid) + ask(R[rt], mid + 1, ar, mid + 1, r); } int main(){ init(); scanf("%d%d", &n, &m); for(int i = 1; i <= n; i ++) scanf("%s", str+1), Insert(i); buildfail(); dfs(root); T[0] = build(1, dfs_clock); for(int i = 1; i <= n; i ++){ T[i] = T[i-1]; for(int j = pos[i]; j; j = fa[j]) T[i] = update(T[i], In[j], 1, dfs_clock); } int l, r, k; for(int i = 1; i <= m; i ++){ scanf("%d%d%d", &l, &r, &k); l --; printf("%d\n", ask(T[r], In[pos[k]], Out[pos[k]], 1, dfs_clock) - ask(T[l], In[pos[k]], Out[pos[k]], 1, dfs_clock)); } return 0; } /* 5 5 a ab abab ababab b 1 5 1 3 5 1 1 5 2 1 5 3 1 4 5 */
给时光以生命,而不是给生命以时光。