20220613

  • rk 3/10, 30+40+100=170
  • max: 100+100+21=221

T1 一开始看了假题,整自闭了。一定要手模样例,花不了多少时间
T3 感觉上可以流,没有严格证明。幸运的是结论对了,以后还是要注意严谨性


签到题

点加、链求和(相当于根链求和)可以转化成子树加、单点求值从而省掉树剖的 \(\log\)

lxl:你们数据结构基础不扎实啊

code

赛时写的 \(\log^{2}\)

const int N = 2e5+5;
int n,m,ind,a[N],w[N],fa[N],dep[N],siz[N],son[N],top[N],dfn[N],id[N];
Vi e[N];
int stk[N],tp;

struct FT {
	LL t[N];
	void add(int i,int x) { for(;i<=ind;i+=i&-i)t[i]+=x; }
	LL sum(int l,int r) const {
		LL res=0; ckmax(l,1);
		for(--l;r>l;r-=r&-r)res+=t[r]; for(;l>r;l-=l&-l)res-=t[l];
		return res;
	}
	LL operator [] (int i) const { return sum(i,i); }
} val,add;

void dfs1(int u) {
	dep[u] = dep[fa[u]]+1, siz[u] = 1;
	for(int v : e[u]) {
		dfs1(v), siz[u] += siz[v];
		if( siz[v] > siz[son[u]] ) son[u] = v;
	}
}
void dfs2(int u,int t) {
	top[u] = t, dfn[u] = ++ind, id[ind] = u;
	if( son[u] ) dfs2(son[u],t);
	for(int v : e[u]) if( v != son[u] ) dfs2(v,v);
}
int lca(int u,int v) {
	for(; top[u] != top[v]; u = fa[top[u]])
		if( dep[top[u]] < dep[top[v]] ) swap(u,v);
	return dep[u]<dep[v] ? u : v;
}
LL qry(int u,int v,const FT &ft) {
	LL res = 0;
	for(; top[u] != top[v]; u = fa[top[u]]) res += ft.sum(dfn[top[u]],dfn[u]);
	return res+ft.sum(dfn[v],dfn[u]);
}

signed main() { freopen("set.in","r",stdin); freopen("set.out","w",stdout);
	io>>n>>m; For(i,1,n) io>>a[i]; For(i,1,n) io>>w[i];
	a[n+1] = 2e9, stk[++tp] = n+1;
	rFor(i,n,1) {
		int l = 1, r = tp;
		while( l < r ) { int mid = l+r+1>>1; a[i]<a[stk[mid]] ? l=mid : r=mid-1; }
		fa[i] = stk[l], e[stk[l]].pb(i);
		while( a[i] >= a[stk[tp]] ) --tp;
		stk[++tp] = i;
	}
//	cerr<<"fa: "; For(i,1,n) cerr<<fa[i]<<' '; cerr<<endl;
	dfs1(n+1), dfs2(n+1,n+1);
	For(i,1,n) val.add(dfn[i],w[i]);
	while( m-- ) {
		int op,x,y; io>>op>>x>>y;
		if( op == 1 ) val.add(dfn[x],y), add.add(dfn[x],y);
		else {
			if( x > y ) swap(x,y);
			int u = lca(x,y), v = u==y ? fa[u] : u;
			if( v == n+1 ) { io<<"?\n"; continue; }
			if( u == y ) io<<qry(x,v,val)+qry(fa[x],fa[v],add)<<endl;
			else io<<qry(x,v,val)+qry(fa[x],fa[v],add)
					 + qry(y,v,val)+qry(fa[y],fa[v],add)
					 - val[dfn[v]]-add[dfn[fa[v]]]<<endl;
		}
	}
	return 0;
}

蓝超巨星

可以 \(O(n)\) 预处理 \(b\) 次变换后的 \(f\)(连边 \(i\rightarrow f(i)\),在环上走 \(b\) 次),那么可以 \(O(n)\) 进行递进操作

可以搜出来周期最大为 \(1260\),那么答案上界为 \(1260n\)。递进操作可逆,使用 BSGS 可以获得 90pts

设答案为 \(x\)。考虑枚举最后左移了 \(i\) 位,那么 \(ax\equiv i\pmod n\)。若 \(\gcd(a,n)\nmid i\) 则无解,否则把 \(a,i,n\) 都除以 \(\gcd\),乘上 \(a^{-1}\) 变成 \(x\equiv r\pmod m\) 的形式
\(lst[i]\) 为上一个与 \(i\) 相同的位置,维护 \(i-lst[i]\) 的哈希值即可判断字母间是否存在映射。找到对应的字母,那么 \(x\equiv\text{环上位置差}\pmod{\text{环长}}\)。exCRT 解这些同余方程即可

code
namespace Hsh {
typedef pair<LL,LL> H;
const int p1 = 993244853, p2 = 1e9+9;
auto Add=[](auto x,auto y,auto mod) { return x+y<mod?x+y:x+y-mod; };
auto Del=[](auto x,auto y,auto mod) { return x-y<0?x-y+mod:x-y; };
H operator + (const H &x,const H &y)
	{ return {Add(x.fi,y.fi,p1),Add(x.se,y.se,p2)}; }
H operator - (const H &x,const H &y)
	{ return {Del(x.fi,y.fi,p1),Del(x.se,y.se,p2)}; }
H operator * (const H &x,const H &y) { return {x.fi*y.fi%p1,x.se*y.se%p2}; }
H operator + (const H &x,int y) { return {Add(x.fi,y,p1),Add(x.se,y,p2)}; }
H operator * (const H &x,LL y) { return {x.fi*y%p1,x.se*y%p2}; }
} using namespace Hsh;

const int N = 2e5+5;
int n,a,b,ans=inf,lst[26],dis[26][26];
char f[27],s[N*2],t[N*2];
bool vis[26];
H hs,ht,bs[N];
queue<int> pos[26];

bool chk() { For(i,1,n) if( s[i] != t[i] ) return 0; return 1; }

LL exgcd(LL a,LL b,LL &x,LL &y) {
	if( !b ) return x = 1, y = 0, a;
	LL d = exgcd(b,a%b,y,x);
	return y -= a/b*x, d;
}
LL inv(LL a,LL mod) { LL x,y; exgcd(a,mod,x,y); return (x%mod+mod)%mod; }

struct {
	LL r1,m1,x,y;
	void init(LL r2,LL m2) { r1 = r2, m1 = m2; }
	bool mrg(LL r2,LL m2) {
		LL c = (r2-r1%m2+m2)%m2, d = exgcd(m1,m2,x,y);
		if( c % d ) return 0;
		(x *= c/d) %= (m2/d), r1 += x*m1, m1 *= m2/d, r1 = (r1%m1+m1)%m1;
		return 1;
	}
} crt;

signed main() { freopen("blue.in","r",stdin); freopen("blue.out","w",stdout);
	bs[0] = {1,1}, bs[1] = {131,1331}; For(i,2,2e5) bs[i] = bs[i-1] * bs[1];
	io>>n>>a>>b>>f>>s+1>>t+1, a %= n;
	Rep(i,0,26) f[i] -= 'a'; For(i,1,n) s[i] -= 'a', t[i] -= 'a';
	copy(s+1,s+n+1,s+n+1), copy(t+1,t+n+1,t+n+1);
	Rep(i,0,26) if( !vis[i] ) {
		Vi p;
		for(int j = i; !vis[j]; j = f[j]) vis[j] = 1, p.pb(j);
		Rep(j,0,sz(p)) f[p[j]] = p[(j+b)%sz(p)];
	}
//	cerr<<"f: "; Rep(i,0,26) cerr<<f[i]<<' '; cerr<<endl;
	Rep(i,0,26) {
		int cnt = 0;
		for(int j = f[i]; j != i; j = f[j]) dis[i][j] = ++cnt;
		dis[i][i] = ++cnt;
	}
	For(i,1,n) ht = ht*bs[1]+(lst[t[i]]?i-lst[t[i]]:0), lst[t[i]] = i;
	For(i,1,n) hs = hs*bs[1]+(sz(pos[s[i]])?i-pos[s[i]].back():0), pos[s[i]].push(i);
	For(i,1,n) {
		pos[s[i]].pop();
		if( sz(pos[s[i]]) )
			hs = hs - bs[n+i-pos[s[i]].front()-1] * (pos[s[i]].front()-i);
		hs = hs*bs[1]+(sz(pos[s[i]])?n+i-pos[s[i]].back():0), pos[s[i]].push(n+i);
		[&](int r,int m) {
			if( hs != ht ) return;
//			cerr<<i<<endl;
			int d = __gcd(a,m); if( r % d ) return;
			a /= d, r /= d, m /= d;
			crt.init(r*inv(a,m)%m,m);
			Rep(j,0,26) if( sz(pos[j]) ) {
				int k = t[(pos[j].front()-i-1+n)%n+1];
				if( !dis[j][k] || !crt.mrg(dis[j][k],dis[j][j]) ) return;
			}
			ckmin(ans,crt.r1?crt.r1:crt.m1);
		}(i,n);
	}
	io<<(ans==inf?-1:ans);
	return 0;
}

秘密行动

奇怪的最优化考虑流

最小割可以实现把元素分到两个集合中

考场代码
const LD eps = 1e-8;
short cmp(LD x,LD y=0) { return fabs(x-y)<eps ? 0 : x>y ? 1 : -1; }
namespace flow {
const int N = 55;
int S,T,m,head[N],dis[N],now[N];
struct { int nxt,to; LD c; } e[2*(N*2+505)];
void init(int n) { m = 1, S = n+1, T = S+1, mem(head,0,T); }
void add(int x,int y,LD z) { e[++m] = {head[x],y,z}, head[x] = m; }
void addedge(int x,int y,LD z) { add(x,y,z), add(y,x,0); }
bool bfs() {
static int q[N],l,r;
	mem(dis,0,T);
	q[l=r=1] = S, dis[S] = 1, now[S] = head[S];
	while( l <= r ) {
		int u = q[l++];
		for(int i = head[u], v; v = e[i].to, i; i = e[i].nxt)
			if( cmp(e[i].c) && !dis[v] ) {
				q[++r] = v, dis[v] = dis[u]+1, now[v] = head[v];
				if( v == T ) return 1;
			}
	}
	return 0;
}
LD dfs(int u,LD f) {
	if( u == T ) return f;
	LD use = 0;
	for(int i = now[u], v; v = e[i].to, i && cmp(use,f) < 0; i = e[i].nxt)
		if( e[now[u]=i].c && dis[u]+1 == dis[v] ) {
			LD g = dfs(v,min(e[i].c,f-use));
			if( !cmp(g) ) dis[v] = 0;
			else e[i].c -= g, e[i^1].c += g, use += g;
		}
	return use;
}
LD dinic() { LD mf=0; while( bfs() ) mf += dfs(S,1e9); return mf; }
} using flow::S; using flow::T; using flow::addedge;

const int N = 55;
int n,m;

struct {
	int pri;
	LD f,c[N],d[N];
	vector<Pii> a;
	LD main() {
		flow::init(n);
		For(i,1,n) addedge(S,i,log(c[i])), addedge(i,T,log(d[i]));
		f = log(f); for(auto &i : a) flow::add(i.fi,i.se,f), flow::add(i.se,i.fi,f);
		return flow::dinic();
	}
} a[10];

signed main() { freopen("secret.in","r",stdin); freopen("secret.out","w",stdout);
	ios::sync_with_stdio(0);cin.tie(0);
	io>>n>>m;
	For(i,0,9) io>>a[i].pri>>a[i].f;
	For(i,1,n) {
		For(j,0,9) io>>a[j].c[i];
		For(j,0,9) io>>a[j].d[i];
	}
	For(i,1,m, x,y,z) io>>x>>y>>z, a[z-1].a.pb(x,y);
	LD ans=0; For(i,0,9) ans += a[i].main();
	printf("%Lf",exp(ans));
	return 0;
}
posted @ 2022-06-14 22:09  401rk8  阅读(31)  评论(0编辑  收藏  举报