2022NOIPA层联测4
A 字符串还原
删去一个那么 \([1, n/2]\) \([n/2 + 1, n]\) 有一个不变
那么 \(check\) 一下就行了,
赛时理解错了 \(unique\) 挂了 \(20\)
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2000005;
char s[maxn];
int n;
bool fr = 1, delr = 0;
bool fl = 1, dell = 0;
int mid, len;
bool check(){
for(int i = 1; i <= len; ++i)if(s[i] != s[mid + i])return true;
return false;
}
int main(){
scanf("%d%s",&n,s + 1);
if(n % 2 == 0){
printf("NOT POSSIBLE\n");
return 0;
}
len = n >> 1;
mid = len + 1;
for(int i = 1; i <= len; ++i){
if(s[i] != s[len + i + dell]){
if(dell){fl = 0; break;}
dell = 1; --i;
}
}
for(int i = 1; i <= len; ++i){
if(s[i + delr] != s[mid + i]){
if(delr){fr = 0; break;}
delr = 1; --i;
}
}
if(!fl && !fr){
printf("NOT POSSIBLE\n");
}else if(fl && fr && check()){
printf("NOT UNIQUE\n");
}else{
if(fl){ for(int i = 1; i < mid; ++i)printf("%c",s[i]);
}else{ for(int i = mid + 1; i <= n; ++i)printf("%c",s[i]);}
}
return 0;
}
B 数环
不会,弃了
发现性质操作为交换前缀和
然后断环成链怎么搞,不会
C 所有可能
重学广义 \(sam\)
其实是求前面出现的所有子串次数的平方
然后建出 \(sam\) 对应的 \(parent\) 树,进行树剖
每次匹配一个串,在匹配的每个位置修改其到根的 \(endpos\) 集合
线段树维护其集合大小的平方乘上对应字符串数量 \(len - len_{fa}\)
多维护几个值来进行区间修改
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 600005;
int head[maxn], tot;
struct edge{int to, net;}e[maxn];
int fa[maxn], son[maxn], top[maxn], size[maxn], dep[maxn], dfn[maxn], id[maxn];
void add(int u, int v){
e[++tot].net = head[u];
head[u] = tot;
e[tot].to = v;
}
void dfs1(int x){
size[x] = 1;
for(int i = head[x]; i; i = e[i].net){
int v = e[i].to;
fa[v] = x; dep[v] = dep[x] + 1;
dfs1(v);
size[x] += size[v];
son[x] = size[son[x]] > size[v] ? son[x] : v;
}
}
int tim;
void dfs2(int x, int tp){
top[x] = tp; dfn[x] = ++tim; id[tim] = x;
if(son[x])dfs2(son[x], tp);
for(int i = head[x]; i; i = e[i].net){
int v = e[i].to;
if(v == son[x])continue;
dfs2(v, v);
}
}
int cnt = 1, las = 1;
struct note{
int ch[26], len, fa;
}d[maxn];
void insert(int c){
if(d[las].ch[c]){
int fa = las, x = d[las].ch[c];
if(d[fa].len + 1 == d[x].len)las = x;
else{
int now = las = ++cnt;
d[now] = d[x];
d[now].len = d[fa].len + 1;
for(; fa && d[fa].ch[c] == x; fa = d[fa].fa)d[fa].ch[c] = now;
d[x].fa = now;
}
}else{
int fa = las;
int now = las = ++cnt;
d[now].len = d[fa].len + 1;
for(; fa && !d[fa].ch[c]; fa = d[fa].fa)d[fa].ch[c] = now;
if(!fa)d[now].fa = 1;
else{
int x = d[fa].ch[c];
if(d[fa].len + 1 == d[x].len)d[now].fa = x;
else{
int clone = ++cnt;
d[clone] = d[x];
d[clone].len = d[fa].len + 1;
d[x].fa = d[now].fa = clone;
for(; fa && d[fa].ch[c] == x; fa = d[fa].fa)d[fa].ch[c] = clone;
}
}
}
}
struct seg{
struct node{
ll s, val, size, tag, mul;
}t[maxn << 2 | 1];
void push_up(int x){
int ls = x << 1, rs = x << 1 | 1;
t[x].s = t[ls].s + t[rs].s;
t[x].val = t[ls].val + t[rs].val;
t[x].size = t[ls].size + t[rs].size;
t[x].mul = t[ls].mul + t[rs].mul;
}
void upd(int x, int l, int r, ll val){
t[x].tag += val;
t[x].val = t[x].val + 2 * t[x].mul * val + t[x].size * val * val;
t[x].mul += t[x].size * val;
t[x].s += (r - l + 1) * val;
}
void push_down(int x, int l, int r){
int mid = (l + r) >> 1;
upd(x << 1, l, mid, t[x].tag);
upd(x << 1 | 1, mid + 1, r, t[x].tag);
t[x].tag = 0;
}
void built(int x, int l, int r){
if(l == r){
t[x].size = d[id[l]].len - d[d[id[l]].fa].len;
return;
}
int mid = (l + r) >> 1;
built(x << 1, l, mid);
built(x << 1 | 1, mid + 1, r);
push_up(x);
}
void modify(int x, int l, int r, int L, int R){
if(L <= l && r <= R){
upd(x, l, r, 1);
return;
}
if(t[x].tag)push_down(x, l, r);
int mid = (l + r) >> 1;
if(L <= mid)modify(x << 1, l, mid, L, R);
if(R > mid)modify(x << 1 | 1, mid + 1, r, L, R);
push_up(x);
}
ll qmax(){return t[1].val;}
}t;
void update(int x){
while(x){
t.modify(1, 1, cnt, dfn[top[x]], dfn[x]);
x = fa[top[x]];
}
}
char s[maxn], c[maxn];
int l[maxn], r[maxn], n;
void solve(int x){
int now = 1;
for(int i = l[x]; i <= r[x]; ++i){
now = d[now].ch[s[i] - 'a'];
update(now);
}
printf("%lld\n",t.qmax());
}
int main(){
scanf("%d",&n);
for(int i = 1; i <= n; ++i){
scanf("%s",c + 1); int len = strlen(c + 1);
l[i] = r[i - 1] + 1; r[i] = l[i] + len - 1;
for(int j = 1; j <= len; ++j)s[j + r[i - 1]] = c[j];
las = 1; for(int j = 1; j <= len; ++j)insert(c[j] - 'a');
}
for(int i = 2; i <= cnt; ++i)add(d[i].fa, i);
dfs1(1); dfs2(1, 1); t.built(1, 1, cnt);
for(int i = 1; i <= n; ++i)solve(i);
return 0;
}
D 字符串生成
\(f_i\) 表示已经匹配了 \(i\) 位,到匹配 \(n\) 位的期望步数
\(f_i = 1 /2 f_{i + 1} +1 / 2 f_{trans_i} + 1\)
\(trans_i\) 为 \(i + 1\) 失配到的位置
答案为 \(f_0\)
已知 \(f_n = 0\)
式子简单化一下用 \(i\) 代替 \(i + 1\) 有
\(f_i = 2f_ {i - 1}- f_{trans_{i - 1}} - 2\)
把所有 \(f_i\) 用 \(f_0\)表示,用 \(f_n\) 解出来即可
\(trans\) 的求法,我这个比较玄学
有个 \(nxt_i = now\) 比较玄学,不加复杂度不对,加了正确性存在疑问,但是对拍拍不掉,有会的大佬可以解释下
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e6 + 55;
const int mod = 1e9 + 7;
char c[maxn];
int n, nxt[maxn], f[maxn];
int qpow(int x, int y){
int ans = 1;
for(; y; y >>= 1, x = 1ll * x * x % mod)if(y & 1) ans = 1ll * ans * x % mod;
return ans;
}
ll a[maxn], b[maxn];
int main(){
scanf("%s",c + 1);
n = strlen(c + 1);
int las = 0;
for(int i = 2; i <= n; ++i){
while(las && c[las + 1] != c[i])las = nxt[las];
if(c[las + 1] == c[i]) ++las;
nxt[i] = las;
}
for(int i = 1; i < n; ++i){
int now = nxt[i];
while(now && c[now + 1] == c[i + 1])now = nxt[now];
nxt[i] = now;
if(c[now + 1] != c[i + 1])++now;
f[i] = now;
}
a[0] = 1; b[0] = 0;
for(int i = 1; i <= n; ++i){
a[i] = (a[i - 1] + a[i - 1] - a[f[i - 1]]) % mod;
b[i] = (b[i - 1] + b[i - 1] - b[f[i - 1]] - 2) % mod;
a[i] = (a[i] % mod + mod) % mod;
b[i] = (b[i] % mod + mod) % mod;
}
b[n] = mod - b[n];
int ans = 1ll * b[n] * qpow(a[n], mod - 2) % mod;
printf("%d\n",ans);
return 0;
}