20220723
作者:互联网
fft
solve(l,r)
只与区间长度有关,可以改写成始终 \(l=0\)
打表可知每次取最大的 \(2^{k}<n\) 作为分端点最优。递推出 \(f[0]=1,f[i]=2f[i-1]+i2^{i}\) 表示 \([0,2^{i})\) 的答案,每次枚举二进制中的 \(1\),答案为 \(\sum_{\text{n的第i位是1}}(i+1)2^{i+1}+f[i]-(ctz(n)+1)2^{ctz(n)+1}\)
赛时做法是矩乘计算一个区间的答案,动态开点线段树配合光速幂可以做到 \(O(6^{3}\sqrt{r}+6^{2}n\log r)\),和 \(O(n^{2})\) 一个分(有无人教教如何减小矩阵大小)
归纳一下可以得到 \(f[i]=2^{i}+\frac{i(i+1)}{2}2^{i}\),答案为 \(\sum_{\text{n的第i位是1}}2^{i-1}(i^{2}+5i+6)-(ctz(n)+1)2^{ctz(n)+1}\)。这是一个二阶等差乘等比的形式,可以 \(O(1)\) 计算
修改操作相当于区间 \(0,1\) 覆盖,使用 ODT 维护 \(0,1\) 段,变化时更新全局 \(ans\) 即可
code
int n,m;
mint ans,pw1[1<<15|3],pw2[1<<15|3];
mint sum(int n) {
if( n < 0 ) return 0;
switch(n) {
case 0: return 3;
case 1: return 15;
case 2: return 55;
default:
mint pw = pw1[n&32767] * pw2[n>>15];
return 3 + pw*((LL)n*n+5ll*n+6)-12 + pw*(-2*n-4)+16 + pw*2-8;
}
}
struct Node {
int l,r; bool x;
Node(int l=0,int r=0,bool x=0):l(l),r(r),x(x){}
bool operator < (const Node &a) const { return l < a.l; }
}; set<Node> s;
set<Node>::iterator split(int p) {
auto it = s.lower_bound(Node(p));
if( it != s.end() && it->l == p ) return it;
--it;
auto u = *it; s.erase(it);
return s.emplace(u.l,p-1,u.x), s.emplace(p,u.r,u.x).fi;
}
void cov(int l,int r,bool x) {
if( l > r ) return;
auto itr = split(r+1), itl = split(l);
for(auto i = itl; i != itr; i = s.erase(i))
if( i->x ) ans -= sum(i->r)-sum(i->l-1);
s.emplace(l,r,x);
if( x ) ans += sum(r)-sum(l-1);
}
int bs(int l,bool x) {
auto i = split(l); int r = l-1;
while( i->x != x ) r = i->r, i = s.erase(i);
if( l <= r ) s.emplace(l,r,!x);
return i->l;
}
signed main() {
#ifdef FS
freopen("fft1.in","r",stdin);// freopen(".out","w",stdout);
#else
freopen("fft.in","r",stdin); freopen("fft.out","w",stdout);
#endif
ios::sync_with_stdio(0);cout.tie(0);
s.emplace(0,2e9,0);
pw1[0] = pw2[0] = 1; For(i,1,1<<15) pw1[i] = pw1[i-1] * 2;
Rep(i,1,1<<15) pw2[i] = pw2[i-1] * pw1[1<<15];
io>>n>>m; For(i,1,n, l,r) io>>l>>r, cov(l,r,1);
while( m-- ) {
int op,x,p; io>>op>>x;
if( !op ) p = bs(x,0), cov(p,p,1), cov(x,p-1,0);
else p = bs(x,1), cov(p,p,0), cov(x,p-1,1);
int i = bs(0,1)+1;
cout<<(ans-i*Pow(2,i)).x<<endl;
}
return 0;
}
sort
使用 \(x=\sum_{i=1}^{x}1\) 的技巧,枚举 \(i\in[0,n)\),把 \(<i\) 的记做 \(0\),\(\ge i\) 的记做 \(1\),这 \(n\) 个串的和就是原串
状态数变为了 \(2^n\),考虑状压 DP,逐位进行转移(\(f[i,s]\) 表示进行了前 \(i\) 个位置的交换,状态为 \(s\) 的概率)。对初始的 \(n\) 个串同时 DP,复杂度就是 \(O(mn2^{n})\)
code
const int N = 15;
int n,m,U,a[N];
mint f[1<<N],g[1<<N];
signed main() { freopen("sort.in","r",stdin); freopen("sort.out","w",stdout);
io>>n>>m, U = 1<<n; Rep(i,0,n) io>>a[i], --a[i];
Rep(i,0,n) {
int s=0; Rep(j,0,n) s |= (a[j]>=i) << j;
f[s] += 1;
}
while( m-- ) Rep(i,1,n) {
memcpy(g,f,sizeof f), memset(f,0,sizeof f);
For(s,0,U) {
bool x = s>>i-1&1, y = s>>i&1;
if( x == y) f[s] += g[s];
else if( !x && y ) f[s] += g[s] * (1-233), f[s^3<<i-1] += g[s] * 233;
else if( x && !y ) f[s] += g[s] * 233, f[s^3<<i-1] += g[s] * (1-233);
}
}
Rep(i,0,n) {
mint ans; For(s,0,U) ans += (s>>i&1) * f[s];
io<<ans.x<<' ';
}
return 0;
}
sssp
使用结构体 Node
保存从两点间 \(k\) 短路,\(a+b\) 相当于以 \(a\) 的终点(也是 \(b\) 的起点)作为中转,合并得到 \(a\) 的起点到 \(b\) 的终点的路径
设Node f[i,s,t]
表示从 \(s\) 到 \(t\) 的经过 \(i\) 条边的路径,后两维转移可以写成矩乘形式。对第一维倍增,询问时向量乘矩阵
复杂度瓶颈在于 Node
加法,最终只需要知道 \(s\) 到 \(t\) 的 \(k\) 短路,但最终 \(n\) 个中转点每个计算了 \(k\) 条,考虑优化。计算矩阵 \(c=a\times b\) 时先将 \(b\) 转置,那么 \(c[i,j]\) 由 \(a[i,k],b[j,k]\) 合并得到。四元组(长度,\(k\),\(a[i,k]\) 中排名 \(x\),\(b[j,k]\) 中排名 \(y\)),初始只考虑 \(x=y=0\) 的 \(n\) 个元素,线性建堆,每次取出堆顶后放入 \((x,y+1)\),如果 \(y=0\) 再放入 \((x+1,y)\)(其实看码更容易理解)
最终复杂度 \(O((n^{2}+qn)(n+k\log k)\log a)\)
code
typedef tuple<int,int,int,int> Ti;
const int inf = 0x3f3f3f3f;
const int N = 169;
int n,m,q;
Vi e[N][N];
void mrg(const int (*a)[15],const int (*b)[15],int *c) {
static Ti h[N]; int siz = 0;
For(i,1,n) h[siz++] = {a[i][0]+b[i][0],i,0,0};
make_heap(h,h+siz,greater<>());
Rep(i,0,15) {
int val,k,x,y; tie(val,k,x,y) = h[0];
pop_heap(h,h+siz,greater<>()), --siz;
if( val >= inf ) { memset(c+i,0x3f,sizeof(int)*(15-i)); return; }
c[i] = val;
if( i < 14 ) {
auto push=[&](int x,int y) {
h[siz++] = {a[k][x]+b[k][y],k,x,y},
push_heap(h,h+siz,greater<>());
};
push(x,y+1);
if( !y ) push(x+1,y);
}
}
}
struct Mat {
int a[N][N][15]; Mat() { memset(a,0x3f,sizeof a); }
Mat operator * (Mat b) const {
Mat c;
For(i,1,n) Rep(j,1,i) swap(b.a[i][j],b.a[j][i]);
For(i,1,n) For(j,1,n) mrg(a[i],b.a[j],c.a[i][j]);
return c;
}
} f[20];
struct Vec {
int a[N][15]; Vec() { memset(a,0x3f,sizeof a); }
int* operator [] (int i) { return a[i]; }
Vec operator * (Mat b) const {
Vec c;
For(i,1,n) Rep(j,1,i) swap(b.a[i][j],b.a[j][i]);
For(j,1,n) mrg(a,b.a[j],c[j]);
return c;
}
};
signed main() {
#ifdef FS
freopen("sssp13.in","r",stdin); freopen("out","w",stdout);
#else
freopen("sssp.in","r",stdin); freopen("sssp.out","w",stdout);
#endif
ios::sync_with_stdio(0);cout.tie(0);
io>>n>>m>>q; For(i,1,m, x,y) io>>x>>y, e[x][y].pb(read());
For(i,1,n) For(j,1,n) {
sort(all(e[i][j]));
Rep(k,0,min(15,sz(e[i][j]))) f[0].a[i][j][k] = e[i][j][k];
}
For(i,1,19) f[i] = f[i-1] * f[i-1];
while( q-- ) {
int s,t,a,k; io>>s>>t>>a>>k;
Vec g; g[s][0] = 0;
For(i,0,19) if( a>>i & 1 ) g = g * f[i];
int ans = g[t][k-1];
cout<<(ans<inf?ans:-1)<<endl;
}
return 0;
}
标签:Node,const,int,20220723,15,freopen,return 来源: https://www.cnblogs.com/401rk8/p/16546123.html