#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
*/