ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

20220723

2022-08-03 10:31:15  阅读:130  来源: 互联网

标签:Node const int 20220723 15 freopen return


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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有