CSP-S模拟16
A. 猜道路
直接弗洛伊德即可,不知道为啥脑抽,想了半年建最小生成树
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
inline int read(){
int x = 0; char c = getchar();
while(c < '0' || c > '9')c = getchar();
do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c <= '9' && c >= '0');
return x;
}
const int maxn = 505;
int n, tot, cnt;
int mp[maxn][maxn];
bool del[maxn][maxn];
int main(){
n = read();
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
mp[i][j] = read();
bool fl = 1;
for(int k = 1; k <= n && fl; ++k)
for(int i = 1; i <= n && fl; ++i)
for(int j = 1; j <= n; ++j)
if(i != k && i != j && j != k){
if(mp[i][k] + mp[k][j] < mp[i][j]){
fl = 0; break;
}
if(mp[i][k] + mp[k][j] == mp[i][j])del[i][j] = del[j][i] = 1;
}
if(fl){
ll ans = 0;
for(int i = 1; i <= n; ++i)
for(int j = 1; j < i; ++j)
if(!del[i][j])ans += mp[i][j];
printf("%lld\n",ans);
}else printf("-1\n");
return 0;
}
B. 简单环
考场脑抽,想了半年建树
确实建树,然后发现一个环只要与另外一个环有交就都不合法,于是随机权值异或
不过好像 \(Tarjan\) 一下就行?
不管了
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
inline int read(){
int x = 0; char c = getchar();
while(c < '0' || c > '9')c = getchar();
do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c <= '9' && c >= '0');
return x;
}
mt19937_64 rd((ull)(new char) * (ull)(new char));
ll srd(){
uniform_int_distribution<ll>d(1, 9223372036854775807);
return d(rd);
}
const int maxn = 1000005;
int f[maxn];
int fa(int x){return f[x] == x ? x : f[x] = fa(f[x]);}
int head[maxn], tot;
struct edge{int to, net, id;}e[maxn << 1 | 1];
void add(int u, int v, int w){
e[++tot].net = head[u];
head[u] = tot;
e[tot].to = v;
e[tot].id = w;
}
int ru[maxn], rv[maxn], rc[maxn], rid[maxn], cnt;
ll rval[maxn], val[maxn];
int n, m;
int son[maxn], size[maxn], top[maxn], dep[maxn], id[maxn];
void dfs1(int x){
size[x] = 1;
for(int i = head[x]; i; i = e[i].net){
int v = e[i].to;
if(v == f[x])continue;
dep[v] = dep[x] + 1;
f[v] = x;
id[v] = e[i].id;
dfs1(v);
size[x] += size[v];
son[x] = size[son[x]] > size[v] ? son[x] : v;
}
}
void dfs2(int x, int tp){
top[x] = tp;
if(son[x])dfs2(son[x], tp);
for(int i = head[x]; i; i = e[i].net){
int v = e[i].to;
if(v == f[x] || v == son[x])continue;
dfs2(v, v);
}
}
int lca(int u, int v){
while(top[u] != top[v]){
if(dep[top[u]] < dep[top[v]])swap(u, v);
u = f[top[u]];
}
if(dep[u] < dep[v])return u;
return v;
}
unordered_map<ll, int>mp;
void dfs3(int x){
for(int i = head[x]; i; i = e[i].net){
int v = e[i].to;
if(v == f[x])continue;
dfs3(v);
val[x] ^= val[v];
}
if(x != 1)++mp[val[x]];
}
vector<int>v;
int main(){
n = read(), m = read();
for(int i = 1; i <= maxn - 3; ++i)f[i] = i;
for(int i = 1; i <= m; ++i){
int u = read(), v = read();
if(fa(u) == fa(v)){
++cnt; ru[cnt] = u; rv[cnt] = v; rval[cnt] = srd(); rid[cnt] = i;
}else{add(u, v, i); add(v, u, i); f[fa(u)] = fa(v);}
}
for(int i = 1; i <= n; ++i)f[i] = 0;
for(int i = 1; i <= n; ++i)if(dep[i] == 0)dfs1(i), dfs2(i, i);
for(int i = 1; i <= cnt; ++i){
int lc = lca(ru[i], rv[i]);
rc[i] = dep[ru[i]] + dep[rv[i]] - dep[lc] - dep[lc];
val[ru[i]] ^= rval[i]; val[rv[i]] ^= rval[i];
}
for(int i = 1; i <= n; ++i)if(dep[i] == 0)dfs3(i);
int ans = 0;
for(int i = 1; i <= cnt; ++i){
cerr << ru[i] << " " << rv[i] << endl;
if(mp[rval[i]] != rc[i])continue;
ans += rc[i] + 1;
int lc = lca(ru[i], rv[i]);
int u = ru[i];
while(dep[u] && u != lc){v.push_back(id[u]); u = f[u];}
u = rv[i];
while(dep[u] && u != lc){v.push_back(id[u]); u = f[u];}
v.push_back(rid[i]);
}
if(ans)sort(v.begin(), v.end());
printf("%d\n",ans);
for(int x : v)printf("%d ",x);
return 0;
}
C. 汉明距离
开始看到时限 \(15000ms\) 加上脑抽,算出来直接暴力能过》
然而不行
正解 \(FFT\) 科技,比较离谱
设 \(H(x)\) 表示从 \(x\) 开始的答案
\(H(x ) = \sum_{i =x}^{x + m - 1}(a_i - b_i)^2 = \sum_{i = x}^{x + m - 1}a_i^2+b_i^2-2a_ib_i\)
两个平方项前缀和预处理,后面那个发现是差卷积的形式,取的是卷积后第 \(x\) 项系数
差卷积可以直接 \(nfft\) \(g\) 但是不除以 \(n\) ,然后与 \(fft\) 的 \(f\) 卷即可
比较神奇,多项式。。。。。如果。。。。。。。。。
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
inline int read(){
int x = 0; char c = getchar();
while(c < '0' || c > '9')c = getchar();
do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c <= '9' && c >= '0');
return x;
}
const int maxn = 3000005;
const int mod = 998244353;
ll qpow(ll x, ll y){
ll ans = 1;
for(; y; y >>= 1, x = x * x % mod)if(y & 1)ans = ans * x % mod;
return ans;
}
int rev[maxn];
void getrev(int len){
for(int i = 0; i < len; ++i){
rev[i] = rev[i >> 1] >> 1;
if(i & 1)rev[i] |= len >> 1;
}
}
inline void ntt(int a[], int len){
for(int i = 1; i < len; ++i)if(i < rev[i]) swap(a[i], a[rev[i]]);
for(int l = 2; l <= len; l <<= 1){
ll wn = qpow(3, (mod - 1) / l), p = l >> 1;
for(int j = 0; j < len; j += l){
ll w = 1;
for(int k = j; k < j + p; ++k){
ll x = a[k], y = w * a[k + p] % mod;
a[k] = (x + y) % mod; a[k + p] = (x - y + mod) % mod;
w = w * wn % mod;
}
}
}
}
void intt(int a[], int len, bool op){
ntt(a, len); reverse(a + 1, a + len);
if(op)return;
ll inv = qpow(len, mod - 2);
for(int i = 0; i < len; ++i)a[i] = a[i] * inv % mod;
}
int f[maxn], g[maxn], h[maxn];
char a[maxn], b[maxn];
int la, lb, sa[maxn], sb[maxn];
int main(){
scanf("%s%s",a, b);
la = strlen(a); lb = strlen(b);
for(int i = 0; i < la; ++i)f[i] = a[i] - '0';
for(int i = 0; i < lb; ++i)g[i] = b[i] - '0';
sa[0] = a[0] == '1';for(int i = 1; i < la; ++i)sa[i] = sa[i - 1] + a[i] - '0';
sb[0] = b[0] == '1';for(int i = 1; i < lb; ++i)sb[i] = sb[i - 1] + b[i] - '0';
int mx = 1; while(mx < la + lb - 1)mx <<= 1;
getrev(mx);
ntt(f, mx);
intt(g, mx, 1);
for(int i = 0; i < mx; ++i)h[i] = 1ll * f[i] * g[i] % mod;
intt(h, mx, 0);
int ans = lb;
for(int i = 0; i + lb <= la; ++i){
if(i) ans = min(ans, ((sa[i + lb - 1] - sa[i - 1] + sb[lb - 1] - 2 * h[i]) % mod + mod) % mod);
else ans = min(ans, ((sa[i + lb - 1] + sb[lb - 1] - 2 * h[i]) % mod + mod) % mod);
}
printf("%d\n",(ans % mod + mod) % mod);
return 0;
}
D. 勇者的后缀
我是 *****
考场写出 \(sa\) 但是只会暴力
。。。。。。。。。。。。。。。。。
然后建主席树,在对应区间查询 \(rk_{i}\) 的前驱后继,取 \(maxlcp\) 为 \(len\), 然后在前面二分得到 \(min(rk)\) 使得 \(lcp(minrk,x) == len\) 然后在主席树对应区间查询后继
主席树无法直接查前驱后继,先查排名然后查排名\(+/- 1\)即可
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
inline int read(){
int x = 0; char c = getchar();
while(c < '0' || c > '9')c = getchar();
do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c <= '9' && c >= '0');
return x;
}
const int maxn = 200055;
int root[maxn];
struct pst{
struct node{
int l, r, size;
}t[maxn * 30];
int cnt;
void push_up(int x){t[x].size = (t[t[x].l].size + t[t[x].r].size);}
void insert(int &x, int y, int l, int r, int pos){
if(!x) x = ++cnt;
if(l == r){
assert(x);
++t[x].size;
return;
}
int mid = (l + r) >> 1;
t[x] = t[y];
if(pos <= mid)t[x].l = 0, insert(t[x].l, t[y].l, l, mid, pos);
else t[x].r = 0, insert(t[x].r, t[y].r, mid + 1, r, pos);
push_up(x);
}
int get_rk(int x, int y, int l, int r, int val){
if(t[x].size - t[y].size == 0)return 0;
if(l == r){
if(l <= val)return t[x].size;
return 0;
}
int mid = (l + r) >> 1;
if(val <= mid)return get_rk(t[x].l, t[y].l, l, mid, val);
else return t[t[x].l].size - t[t[y].l].size + get_rk(t[x].r, t[y].r, mid + 1, r, val);
}
int que_rk(int x, int y, int l, int r, int rk){
if(rk < 1 || t[x].size - t[y].size < rk)return -1;
if(l == r)return l;
int mid = (l + r) >> 1;
if(rk <= t[t[x].l].size - t[t[y].l].size)return que_rk(t[x].l, t[y].l, l, mid, rk);
else return que_rk(t[x].r, t[y].r, mid + 1, r, rk - t[t[x].l].size + t[t[y].l].size);
}
}t;
int sa[maxn], rk[maxn], ht[maxn], cnt[maxn + maxn], ork[maxn + maxn], px[maxn + maxn], id[maxn];
bool cmp(int x, int y, int w){return ork[x] == ork[y] && ork[x + w] == ork[y + w];}
char c[maxn];
struct SA{
int n, m = 300;
void built(){
m = max(n, m);
for(int i = 1; i <= n; ++i)++cnt[rk[i] = c[i]];
for(int i = 1; i <= m; ++i)cnt[i] += cnt[i - 1];
for(int i = n; i >= 1; --i)sa[cnt[rk[i]]--] = i;
for(int i = 1; i <= m; ++i)cnt[i] = 0;
int p = 0;
for(int w = 1; w <= n; w <<= 1){
p = 0;
for(int i = n; i > n - w; --i)id[++p] = i;
for(int i = 1; i <= n; ++i)if(sa[i] > w)id[++p] = sa[i] - w;
for(int i = 1; i <= n; ++i)++cnt[px[i] = rk[id[i]]];
for(int i = 1; i <= m; ++i)cnt[i] += cnt[i - 1];
for(int i = n; i >= 1; --i)sa[cnt[px[i]]--] = id[i];
for(int i = 1; i <= m; ++i)cnt[i] = 0;
p = 0;
for(int i = 1; i <= n; ++i)ork[i] = rk[i];
for(int i = 1; i <= n; ++i){
if(cmp(sa[i], sa[i - 1], w))rk[sa[i]] = p;
else rk[sa[i]] = ++p;
}
if(p == n)break;
m = p;
}
}
void get_ht(){
int k = 0;
for(int i = 1; i <= n; ++i){
if(k) --k;
while(c[i + k] == c[sa[rk[i] - 1] + k]) ++k;
ht[rk[i]] = k;
}
}
int st[maxn][19];
int lg[maxn];
void get_st(){
for(int i = 2; i <= n; ++i)lg[i] = lg[i >> 1] + 1;
for(int i = 1; i <= n; ++i)st[i][0] = ht[i];
for(int j = 1; (1 << j) <= n; ++j)
for(int i = 1; i + (1 << j) - 1 <= n; ++i)
st[i][j] = min(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
}
int get_lcp_pos(int x, int y){
if(x == y)return n - x + 1;
x = rk[x], y = rk[y];
if(x > y)swap(x, y);
++x;
int k = lg[y - x + 1];
return min(st[x][k], st[y - (1 << k) + 1][k]);
}
int get_lcp_rk(int x, int y){
if(x > y)swap(x, y);
++x; int k = lg[y - x + 1];
return min(st[x][k], st[y - (1 << k) + 1][k]);
}
int bound(int l, int r, int len, int qrk){
int ans = r; --r;
while(l <= r){
int mid = (l + r) >> 1;
if(get_lcp_rk(mid, qrk) == len)ans = mid, r = mid - 1;
else l = mid + 1;
}
return ans;
}
void solve(){
int q = read();
for(int ask = 1; ask <= q; ++ask){
int x = read(), l = read(), r = read();
int rkx = t.get_rk(root[r], root[l - 1], 1, n, rk[x]);
int prk = t.que_rk(root[r], root[l - 1], 1, n, rkx);
int nrk = t.que_rk(root[r], root[l - 1], 1, n, rkx + 1);
int len = 0, pos = 0, lenl = 0, lenr = 0;
if(prk != -1)lenl = prk == rk[x] ? n - x + 1 : get_lcp_rk(prk, rk[x]);
if(nrk != -1)lenr = get_lcp_rk(rk[x], nrk);
len = max(lenl, lenr);
if(prk != -1 && len == lenl){
int rkm = bound(1, prk, len, rk[x]);
int rkrkm = t.get_rk(root[r], root[l - 1], 1, n, rkm - 1) + 1;
int posrk = t.que_rk(root[r], root[l - 1], 1, n, rkrkm);
pos = sa[posrk];
}else pos = sa[nrk];
printf("%d %d\n", len, pos);
}
}
void init(){
scanf("%s",c + 1);
n = strlen(c + 1);
built(); get_ht(); get_st();
for(int i = 1; i <= n; ++i)t.insert(root[i], root[i - 1], 1, n, rk[i]);
solve();
}
}s;
int main(){
s.init();
return 0;
}