20220610
- rk 12/40, 77+31+55=163
- max: 100,100,100,95+100+100=295
没有执行好策略。认为 T2 不可做因此没有想,签到失败;花了过多时间思考T3 (但是是无效的)导致 T1 没时间检查
T3 完全没有想到点分治,还是要定时复习
CF571E
为数不多码量大于思维的数学题
套路的分质因子考虑。设 \(a[i,j],b[i,j],res[i]\) 分别为 \(a_{j},b_{j},ans\) 中 \(p_{i}\) 的指数,\(\forall i,j,res[i]=a[i,j]+c[j]b[i,j]\)。然后做一些处理:
- \(\forall j,b[i,j]=0\):所有 \(a[i,j]\) 相等时删除 \(p_i\) 并给答案乘上 \(p_{i}^{a[i,j]}\);否则无解
- \(\exists j,b[i,j]=0\):\(res[i]=a[i,j]\),可以解出一个 \(c[k](b[i,k]\ne0)\),据此算出所有 \(res\) 并检验即可
- \(b[0],b[1]\) 线性相关:若 \(a[0],a[1]\) 对应的比值不同则无解;否则 \(res[0],res[1]\) 成比例,可以删去 \(p_1\),解出 \(res[0]\) 后推出 \(p_1\)
终止状态有两种:
- \(b[0],b[1]\) 不线性相关:可以找到一个 \(\frac{b[0,0]}{b[1,0]}\ne\frac{b[0,j]}{b[1,j]}\) 的 \(j\) 并解出 \(c[0]\)
- 只剩下一个质数 \(p_0\):得到一堆同余方程,\(res[0]\equiv a[0,j]\pmod{b[0,j]}\),exCRT即可。值得一提的是模数只有 \(\log\) 级别,所以可以暴力做
code
#define no io<<-1,exit(0)
const int N = 100;
int n,ans=1,A[N],B[N],c[N];
Vi p,o;
struct Node {
int p,res; Vi a,b;
Node(int p=0,int res=0,Vi a={},Vi b={}):p(p),res(res),a(a),b(b){}
}; vector<Node> vec;
void sieve(int n) {
bitset<int(5e4)+1> vis;
For(i,2,n) {
if( !vis[i] ) p.pb(i);
for(int j = 0; j < sz(p) && i*p[j] <= n; ++j) {
vis[i*p[j]] = 1;
if( !(i % p[j]) ) break;
}
}
}
void fac(int x) {
for(int i = 0; i < sz(p) && p[i]*p[i] <= x; ++i) if( !(x % p[i]) ) {
o.pb(p[i]);
while( !(x % p[i]) ) x /= p[i];
} if( x > 1 ) o.pb(x);
}
void output(int x) {
for(auto &i : vec) i.res = i.a[x] + c[x] * i.b[x];
for(auto &i : vec) Rep(j,0,n)
if( !i.b[j] ) {
if( i.res != i.a[j] ) no;
} else {
if( i.res < i.a[j] || (i.res-i.a[j]) % i.b[j] ) no;
if( !~c[j] ) c[j] = (i.res-i.a[j])/i.b[j];
else if( c[j] != (i.res-i.a[j])/i.b[j] ) no;
}
for(auto &i : vec) (ans *= Pow(i.p,i.res)) %=mod;
io<<ans;
exit(0);
}
void sub1(const Node &x,int y) { cerr<<"sub1\n";
Rep(j,0,n) if( x.b[j] ) {
if( y < x.a[j] || (y-x.a[j]) % x.b[j] ) no;
c[j] = (y-x.a[j]) / x.b[j], output(j);
}
ast(0);
}
void sub2(const Node &x,const Node &y,int j) { cerr<<"sub2\n";
c[0] = (x.a[j]*y.b[j]-y.a[j]*x.b[j]+y.a[0]*x.b[j]-x.a[0]*y.b[j]) /
(x.b[0]*y.b[j]-y.b[0]*x.b[j]);
output(0);
}
void sub3(const Node &x) { cerr<<"sub3\n"<<endl;
#ifdef FS
Rep(j,0,n) cerr<<"= "<<x.a[j]<<" (mod "<<x.b[j]<<")\n";
#endif
int res = 0, m = 1;
Rep(j,0,n) {
for(int cnt = 0; res%x.b[j] != x.a[j]%x.b[j]; ++cnt) {
if( cnt > x.b[j] ) no;
res += m;
}
m = m / __gcd(m,x.b[j]) * x.b[j];
}
cerr<<"res = "<<res<<endl;
Rep(j,0,n) while( res < x.a[j] ) res += m;
io<<ans*Pow(x.p,res)%mod;
exit(0);
}
signed main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout);
sieve(5e4);
memset(c,0xff,sizeof c);
io>>n; if( n == 1 ) io<<read(), exit(0);
Rep(i,0,n) fac(A[i]=read()), fac(B[i]=read());
sort(all(o)), o.erase(unique(all(o)),o.end());
vec.resize(sz(o));
Rep(i,0,sz(o)) {
vec[i].p = o[i], vec[i].a.resize(n), vec[i].b.resize(n);
Rep(j,0,n) {
while( !(A[j] % o[i]) ) A[j] /= o[i], ++vec[i].a[j];
while( !(B[j] % o[i]) ) B[j] /= o[i], ++vec[i].b[j];
}
}
for(auto i = vec.begin(); i != vec.end(); )
if( !*max_element(all(i->b)) ) {
if( *min_element(all(i->a)) != *max_element(all(i->a)) ) no;
(ans *= Pow(i->p,i->a[0])) %=mod, i = vec.erase(i);
} else ++i;
if( !sz(vec) ) io<<ans, exit(0);
#ifdef FS
for(auto &i : vec) {
cerr<<i.p<<":\n";
Rep(j,0,n) cerr<<i.a[j]<<' '<<i.b[j]<<endl;
} cerr<<endl;
#endif
for(auto &i : vec) Rep(j,0,n) if( !i.b[j] ) sub1(i,i.a[j]);
while( sz(vec) > 1 ) {
Rep(j,1,n) if( vec[0].b[0]*vec[1].b[j] != vec[0].b[j]*vec[1].b[0] )
sub2(vec[0],vec[1],j);
Rep(j,0,n) if( vec[0].b[j]*vec[1].a[j] != vec[1].b[j]*vec[0].a[j] ) no;
if( vec[0].b[0] > vec[1].b[0] ) swap(vec[0],vec[1]);
(vec[0].p *= Pow(vec[1].p,vec[1].b[0]/vec[0].b[0])) %=mod,
vec.erase(vec.begin()+1);
}
sub3(vec[0]);
}
ARC093E
记原图 MST 为 \(T\),权值为 \(y\),\(f(u,v)\) 为 \(u,v\) 间最大边
key observation:同时包含黑白色边的 MST 一定是 \(T\) 或在 \(T\) 的基础上用 \((u,v,w)\) 替换 \(f(u,v)\)
- \(T\) 中边不同色:当且仅当 \(x=y\) 时贡献 \((2^{n-1}-2)2^{m-n+1}\)
- \(T\) 中边同色:\(y+w-f(u,v)<x\) 的边不能加入,必须和 \(T\) 同色。设有 \(a\) 条边满足 \(y+w-f(u,v)=x\),\(b\) 条边 \(y+w-f(u,v)>x\),贡献 \(2\times(2^{a}-1)2^{b}\)
时间复杂度 \(O(nm)\) 或 \(O(m\log m)\)
code
const int N = 2e3+5;
int n,m,a,b,fa[N],dep[N],val[N];
LL f,g;
vector<Pii> to[N];
bitset<N> vis;
struct Edge { int u,v,w; } e[N];
int find(int x) { return fa[x]==x ? x : fa[x]=find(fa[x]); }
bool mrg(int x,int y) {
if( (x=find(x)) == (y=find(y)) ) return 0;
return fa[x] = y, 1;
}
void adde(int x,int y,int z) { to[x].pb(y,z), to[y].pb(x,z), g += z; }
#define v ei.fi
void dfs(int u) {
dep[u] = dep[fa[u]]+1;
for(auto &ei : to[u]) if( v != fa[u] )
fa[v] = u, val[v] = ei.se, dfs(v);
}
#undef v
int qry(int u,int v) {
int res = INT_MIN;
if( dep[u] < dep[v] ) swap(u,v);
while( dep[u] > dep[v] ) ckmax(res,val[u]), u = fa[u];
while( u != v ) ckmax(res,max(val[u],val[v])), u = fa[u], v = fa[v];
return res;
}
signed main() { freopen("b.in","r",stdin); freopen("b.out","w",stdout);
io>>n>>m>>f; For(i,1,m) io>>e[i].u>>e[i].v>>e[i].w;
iota(fa+1,fa+n+1,1),
sort(e+1,e+m+1,[](const Edge &x,const Edge &y){return x.w<y.w;});
For(i,1,m) if( vis[i] = mrg(e[i].u,e[i].v) ) adde(e[i].u,e[i].v,e[i].w);
fa[1] = 0, dfs(1);
For(i,1,m) if( !vis[i] ) {
LL h = g+e[i].w-qry(e[i].u,e[i].v);
if( h == f ) ++a;
else if( h > f ) ++b;
}
io<<((f==g)*Del(Pow(2,n-1),2)*Pow(2,m-n+1) +
2*Del(Pow(2,a),1)*Pow(2,b)) %mod;
return 0;
}
Network
路径问题还是要考虑点分治
这份题解写的很好
code
const int N = 1e5+5;
int n,rt,f[N],siz[N],mxsz[N],mx[N],mn[N];
bool op[N],del[N];
Vi subv;
vector<Vi> sub;
vector<Pii> e[N];
struct {
int dep[N],mx[N][17],mn[N][17];
bool ok[N],vis[N];
Vi sub[N];
void add(int u)
{ sub[rt].pb(u), mx[u][++dep[u]] = ::mx[u], mn[u][dep[u]] = ::mn[u]; }
int main(int lim) {
mem(ok,0,n), mem(vis,0,n);
For(i,1,n) if( !op[i] ) ok[i] = 1, vis[i] = f[i]<lim;
For(u,1,n) { // 枚举分治中心
int d = dep[u], pmn = -inf, smx = inf;
for(int v : sub[u]) { // 用 mx[v]
if( ok[v] && pmn > -inf ) ok[v] &= mx[v][d]-min(mn[v][d],pmn) >= lim;
if( vis[v] ) ckmax(pmn,mn[v][d]);
}
rFor(i,sz(sub[u])-1,0) { int v = sub[u][i]; // 不用 v(u=v)或用 mn[v]
if( ok[v] && smx < inf ) ok[v] &= smx-mn[v][d] >= lim;
if( vis[v] && mx[v][d]-mn[v][d] < lim ) ckmin(smx,mx[v][d]);
} // 不用判断两点是否来自同一子树(极差不会变小,不影响判断)
}
For(i,1,n) if( ok[i] ) return i; return 0;
}
void dbg() {
For(i,1,n) {
cerr<<i<<": "<<dep[i]<<endl;
for(int j : sub[i]) cerr<<j<<' '; cerr<<endl;
}
}
} dt;
void getrt(int u,int fa) {
siz[u] = mxsz[u] = 1;
for(auto &ei : e[u]) { int v = ei.fi;
if( !del[v] && v != fa )
getrt(v,u), siz[u] += siz[v], ckmax(mxsz[u],siz[v]);
}
ckmax(mxsz[u],siz[0]-siz[u]);
if( mxsz[u] < mxsz[rt] ) rt = u;
}
void dfs(int u,int fa) {
subv.pb(u), dt.add(u);
for(auto &ei : e[u]) { int v,w; tie(v,w) = ei;
if( !del[v] && v != fa )
mx[v] = max(mx[u],w), mn[v] = min(mn[u],w), dfs(v,u);
}
}
void slv(int u,int size) {
siz[rt=0] = size, getrt(u,0), del[u=rt] = 1;
mx[u] = -inf, mn[u] = inf, dt.add(u), sub = {{u}};
for(auto &ei : e[u]) { int v,w; tie(v,w) = ei;
if( !del[v] )
subv.clear(),
mx[v] = max(mx[u],w), mn[v] = min(mn[u],w), dfs(v,u),
sub.pb(subv);
}
sort(all(dt.sub[u]),[&](int x,int y){return mx[x]<mx[y];});
auto work=[&]() {
int pmx = -inf, pmn = inf, pf = -inf;
for(auto &i : sub) {
for(int j : i) if( !op[j] && pf > -inf )
ckmax(f[j],max({pf,max(pmx,mx[j])-mn[j],mx[j]-min(pmn,mn[j])}));
for(int j : i) if( op[j] )
ckmax(pmx,mx[j]), ckmin(pmn,mn[j]), ckmax(pf,max(0,mx[j]-mn[j]));
}
}; work(), reverse(all(sub)), work();
for(auto &ei : e[u]) { int v = ei.fi;
if( !del[v] ) slv(v,size-mxsz[v]);
}
}
signed main() { freopen("c.in","r",stdin); freopen("c.out","w",stdout);
io>>n; For(i,1,n) io>>op[i];
Rep(i,1,n, x,y,z) io>>x>>y>>z, e[x].pb(y,z), e[y].pb(x,z);
mxsz[0] = n, slv(1,n);
// cerr<<"f: "; For(i,1,n) cerr<<f[i]<<' '; cerr<<endl;
// dt.dbg();
int l = 0, r = 1e9;
while( l < r ) { int mid = l+r+1>>1; dt.main(mid) ? l=mid : r=mid-1; }
io<<dt.main(l)<<' '<<(l==1e9?0:l);
return 0;
}