【无标题】

E. Sum of Matchings代码
蜗蜗的数列代码
H. Crystalfly代码
F. Towers代码
C. Werewolves代码
P4766 CERC2014 Outer space invaders代码
H. The Boomsday Project代码
Perfect Matchings代码
Binary Strings代码
ACM Tax代码
代码
代码

写这玩意真的麻了!!!!

vector<int> G[N], v;
bool dis[N];
int n;
int c2(int x){return x*(x-1)/2;}
// 判断是否 e 在两个范围内;
bool di(int a, int b, int c, int d, int e){return (e <= n && e >= a && e <= b) || (e > n && e <= d && e >= c);}
// 求环 
void dfs(int u)
{
	for(auto x : G[u]) if(!dis[x]) dis[x] = 1, dfs(x), v.push_back(x);
	return ;
}


int main() 
{
	LL ans = 0;
	scanf("%d", &n);
	for(int i = -n+1;i <= n;i ++)
	{
		int x, y;
		scanf("%d%d", &x, &y);
		G[x].push_back(y);
		G[y].push_back(x);
	}
	for(int i = 1;i <= n;i ++) // 因为是一边指向另一边, 最大匹配数 =  边的数量+1>>1 ;
		if(!dis[i])
		{
			v.clear();
			dfs(i);
			int siz = v.size();
			int a, b, c, d; a = c = n<<2, b = d = 0;
			for(auto x : v) 
				if(x > n) d = max(d, x), c = min(c, x);
				else  a = min(a, x), b = max(b, x);
			ans += 1LL*(siz+1)/2*a*(c-n)*(n-b+1)*(2*n-d+1);
			// 先求全部的 
			for(int l = 0;l < siz;l ++)
			{
				int a, b, c, d, e = v[(l-1+siz)%siz];
				a = c = n<<2+1, b = d = 0;
				if(v[l] > n) d = c = v[l];
				else a = b = v[l];

				for(int r = (l+1)%siz;(r+1)%siz != l;(r += 1) %= siz)
				{
					if(v[r] > n) d = max(d, v[r]), c = min(c, v[r]);
					else  a = min(a, v[r]), b = max(b, v[r]);

					int k = v[(r+1)%siz];
					if(di(a, b, c, d, e) || di(a, b, c, d, k)) continue;
					// 从这开始 都是 sb 求 范围 
					vector<int> q, s;
					q.push_back(0); q.push_back(n+1);     
					s.push_back(n); s.push_back(n+n+1);
					e <= n ? q.push_back(e) : s.push_back(e);
					k <= n ? q.push_back(k) : s.push_back(k);
					sort(all(q));
					sort(all(s));
					
					int aa = *(upper_bound(q.begin(), q.end(), a)-1), 
						bb = *lower_bound(q.begin(), q.end(), b),
						cc = *(upper_bound(all(s), c)-1),
						dd = *lower_bound(all(s), d);
	
					ans += 1LL*((r-l+siz)%siz+1)/2*(a-aa)*(bb-b)*(c-cc)*(dd-d);
				}
			}
		}

差分真神奇,原来还可以这样差分。

int fib[N], a[N];
int n, q, m, num = 0;

void modify(int &a, int b)
{
	if(a) -- num; a = (a+b)%m; if(a) ++ num;
}
int main() 
{ 
	
	scanf("%d%d%d", &n, &q, &m);
	for(int i = 1;i <= n;i ++) scanf("%d", a+i);
	fib[1] = 1;
	for(int i = 2;i <= n;i ++) fib[i] = (fib[i-2] + fib[i-1])%mod;
	for(int i = 1;i <= n;i ++){
		int x;
		scanf("%d", &x);
		a[i] -= x;
	} 
	for(int i = n;i >= 2;i --)
		a[i] = (a[i] - a[i-1]%m - a[i-2]%m + 2*m)%m, num += a[i] != 0;
	num += a[1] != 0;
	while(q --)
	{
		char c[2]; int l, r, f = 1;
		scanf("%s%d%d", c, &l, &r);
		if(c[0] == 'B') f = -1;
		modify(a[l], f*fib[1]);
		if(r+1 <= n) modify(a[r+1], -f*fib[r-l+2]);
		if(r+2 <= n) modify(a[r+2], -f*fib[r-l+1]);
		P(!num);
	}
	return 0;
}

可以算模板题吧,链用树链剖分,个数用主席树统计,再进行查找,查找好像见过类似方法

const int N = 1e5+10, mod = 1e9+7, len = 6100;
void add(int &a, LL b){a = (a+b)%mod;return ;}
LL qsm(LL u, int v){LL ans = 1;for(;v;v>>=1, u=u*u%mod) if(v&1) ans = ans*u%mod;return ans;}
LL inv(int x){return qsm(x, mod-2);}

int h[N],ne[N],e[N],son[N],siz[N], idx, w[N], val[N];
int top[N],fa[N],deep[N],dfn[N],rnk[N],num;
void add(int u, int v, int x){w[idx] = x;e[idx] = v;ne[idx] = h[u]; h[u] = idx++; return ;}

vector<PII> v, c;
int sum = 0;

int rt[N], tr[N<<4], ls[N<<4], rs[N<<4];
void modify(int &u, int v, int l, int r, int x)
{
	u = ++idx;
	ls[u] = ls[v]; rs[u] = rs[v]; tr[u] = tr[v] + 1;
	if(l == r) return ;
	x <= mid ? modify(ls[u], ls[v], l, mid, x) : modify(rs[u], rs[v], mid+1, r, x);
	return ;
}
int quary(int l, int r, int k)
{
	if(l == r) return l;
	int sum = 0;
	for(auto x : v) sum += tr[ls[x.first]]*x.second;
	if(sum >= k) for(auto &x : v) x.first = ls[x.first];
	else for(auto &x : v) x.first  = rs[x.first];
	
	return sum >= k ? quary(l, mid, k) : quary(mid+1, r, k-sum);
}

void dfs1(int u,int f) {
    siz[u] = 1;
    fa[u] = f;
    deep[u]=deep[f]+1;
    for (int i = h[u]; ~i; i = ne[i])
	{
		int t = e[i];
		if(t == f)continue;
		dfs1(t, u);  val[t] = w[i];
		siz[u] += siz[t];
		if(siz[t] > siz[son[u]]) son[u] = t;//娌℃湁0杩欎釜鐐癸紱鏄繖鏍峰啓 
	}
	return ; 
}
void dfs2(int u, int t) {
	dfn[u] = ++num; modify(rt[dfn[u]], rt[dfn[u]-1], 1, 100000, val[u]); 
  	top[u] = t;
  	rnk[num] = u;
  	if(!son[u])return ;
  	dfs2(son[u], t);
  	for(int i = h[u]; ~i;i = ne[i])
  	{
  		int j = e[i];
  		if(j==son[u]||j==fa[u])continue;
  		dfs2(j,j);
	}
	return ;
}

void LCA(int x, int y)
{
	while(top[x] != top[y])  
	{
		if(deep[top[x]] < deep[top[y]]) swap(x, y);
		v.push_back({rt[dfn[x]], 1}); v.push_back({rt[dfn[top[x]]-1], -1});
		sum += deep[x] - deep[fa[top[x]]];
		x = fa[top[x]];
	}
	if(deep[x] < deep[y])swap(x, y);
	v.push_back({rt[dfn[x]], 1});
	v.push_back({rt[dfn[y]], -1});
	sum += deep[x] - deep[y];
}

int main() 
{ 
	int t;
	scanf("%d", &t);
	while(t --)
	{
		int n, q;
		scanf("%d", &n);
		for(int i = 1;i <= n;i ++) h[i] = -1, son[i] = 0;
		num = 0; idx = 0;
		for(int i = 2;i <= n;i ++)
		{
			int u, v, w;
			scanf("%d%d%d", &u, &v, &w);
			add(u, v, w); add(v, u, w);
		}
		idx = 0;
		dfs1(1, 0); dfs2(1, 0);  
		scanf("%d", &q);
		while(q --)
		{
			int l, r;
			scanf("%d%d", &l, &r);
			v.clear(); sum = 0;
			LCA(l, r); c = v; // vector<int> v, c 是节点数组 方便log*log 而不是log*log*log 
			++ sum;
			int k = quary(1, 100000, sum/2);
			v = c;
			k += quary(1, 100000, sum+1>>1);
			printf("%d", k/2);
			puts(k&1 ? ".5" : ".0");
		}
	}
	return 0;
}

直接递归就能算,亏我还数位dp了半天

const int N = 1e5+10, mod = 1e9+7;
void add(int &a, LL b){a = (a+b)%mod;return ;}
void add(LL &a, LL b){a = (a+b)%mod;return ;}
LL qsm(LL u, int v){LL ans = 1;for(;v;v>>=1, u=u*u%mod) if(v&1) ans = ans*u%mod;return ans;}
LL inv(int x){return qsm(x, mod-2);}

struct point{LL a[4];};
point be = {1, 0, 0, 1};

point operator * (point a, point b)
{
	point c = {0};
	add(c.a[0], a.a[0]*b.a[0] + a.a[0]*b.a[2] + a.a[1]*b.a[0]);
	add(c.a[1], a.a[0]*b.a[1] + a.a[0]*b.a[3] + a.a[1]*b.a[1]);
	add(c.a[2], a.a[3]*b.a[0] + a.a[2]*b.a[2] + a.a[2]*b.a[0]);
	add(c.a[3], a.a[3]*b.a[1] + a.a[2]*b.a[1] + a.a[2]*b.a[3]);
	return c;
}
point operator + (point a, point b){for(int i = 0;i < 4;i ++) add(a.a[i], b.a[i]);return a;}
void prin(point a){for(int i = 0;i < 4;i ++) cout<<a.a[i]<<' ';cout<<endl;return ;}

point se(LL k)
{
	point c = be, s = c; k --;
	for(;k;k>>=1, c = c*c) if(k&1) s = s*c;
	return s;
}

point se(LL s, int k)
{
	if(s <= 0) return {0, 0, 0, 0};
	if(s == 1) return se(k);
	LL l = s>>1, r = s-l;
	point t = se(l, k);
	if(l == r) return t + t*se(l*k);
	else return t + t*se(l*k) + se(s*k);
}

int main() 
{ 
	int t;
	scanf("%d", &t);
	for(int i = 1;i <= t;i ++)
	{
		LL L, R, k;
		scanf("%lld%lld%lld", &L, &R, &k);
		-- L;
		point l = se(R/k, k), r = se(L/k, k);
		int ans =  0 ;
		for(int i = 0;i < 4;i ++) add(ans, l.a[i] - r.a[i]);
		add(ans, mod);
		printf("Case %d: %d\n",i, ans);
	}
	return 0;
}

容了半天没容明白,晚上再想想

vector<int> v[N];
int dp[4100][8100][2], siz[4100], n, in[N];

void dfs(int u, int fa)
{
	siz[u] = 1;
	dp[u][0][0] = 1;
	for(auto x : v[u])
	{
		if(x == fa) continue;
		dfs(x, u);
		for(int i = siz[u];i >= 0;i --)
			for(int j = siz[x];j >= 1;j --)
				add(dp[u][i+j][0], 1LL*dp[u][i][0]*(dp[x][j][0] + dp[x][j][1])),
				add(dp[u][i+j][1], 1LL*dp[u][i][1]*(dp[x][j][0] + dp[x][j][1]) + 1LL*dp[u][i][0]*dp[x][j-1][0]);
		siz[u] += siz[x];
	}	

	return ;
}

int main() 
{
	scanf("%d", &n);	
	for(int i = 2*n-1;i >= 1;i --)
	{
		int a, b;
		scanf("%d%d", &a, &b);
		v[a].push_back(b);
		v[b].push_back(a);	
	}	
	in[0] = 1;
	for(int i = 1;i <= n;i ++) in[i] = 1LL*in[i-1]*((i<<1)-1)%mod;
	
	dfs(1, 0);
	int ans = in[n];
	for(int i = 1;i <= n;i ++)
		add(ans, 1LL*(i&1 ? -1 : 1)*(dp[1][i][0]+dp[1][i][1])*in[n-i]); 
    add(ans, mod);
	cout<<ans<<endl;
	return 0;
}

单调栈

int d[510], k[510], c[510], e[N];
int a[N], idx = 0;
LL dp[N];
int main() 
{

	int n, m, r;
	scanf("%d%d%d", &n, &m, &r);
	for(int i = 1;i <= n;i ++) scanf("%d%d%d", d+i, k+i, c+i);
	for(int i = 1;i <= m;i ++)
	{
		int p, q;
		scanf("%d%d", &p, &q);
		while(q --) ++ idx, a[idx] = p;
	}
	sort(a+1, a+idx+1);
	memset(dp, 0x3f, sizeof dp);
	dp[0] = 0; a[0] = -1e9;
	for(int i = 1;i <= idx;i ++)
	{
	//	dp[i] = min(dp[i], dp[i-1]+r);
		for(int j = 1;j <= n;j ++){
			while(a[i]-a[e[j]]+1 > d[j] || i-e[j]+1 > k[j]) ++ e[j];
			dp[i] = min(dp[i], dp[e[j]-1] + c[j]);
		}
	}
	cout<<dp[idx]<<endl;
	return 0;
}

相当于分割吧 n 3 n^3 n3 暴力区间dp

pair<PII, int> a[N];
vector<int> v;
bool dis[610][610];
int dp[610][610], n;

int dfs(int l, int r)
{
	if(dis[l][r]) return dp[l][r];
	dis[l][r] = 1; 
	int c = -1;
	for(int i = 1;i <= n;i ++)
	{
		int x = a[i].first.first, y = a[i].first.second;
		if(x >= l && y <= r && (c == -1 || a[i].second > a[c].second)) c = i;
	}
	if(c == -1) return dp[l][r] = 0;
	int x = a[c].first.first, y = a[c].first.second;
	while(x <= y) dp[l][r] = min(dp[l][r], dfs(l, x-1)+dfs(x+1, r)+a[c].second), ++x;
	return dp[l][r];
}
	
int main() 
{
	
	int t;
	scanf("%d", &t);
	memset(dp, 0x3f, sizeof dp);
	while(t --)
	{
		scanf("%d", &n);
	 	for(int i = 1;i <= n;i ++) scanf("%d%d%d", &a[i].first.first, &a[i].first.second, &a[i].second), v.push_back(a[i].first.first),v.push_back(a[i].first.second);
		v.push_back(-1);
		sort(v.begin(), v.end());
		v.erase(unique(v.begin(), v.end()), v.end());
		
		for(int i = 1;i <= v.size();i ++)for(int j = 1;j <= v.size();j ++) dis[i][j] = 0, dp[i][j] = 0x3f3f3f3f;
		
		for(int i = 1;i <= n;i ++){
			int &x = a[i].first.first;
			int &y = a[i].first.second;
			x = lower_bound(v.begin(), v.end(), x) - v.begin();
			y = lower_bound(v.begin(), v.end(), y) - v.begin();
		}
		cout<<dfs(1, v.size()-1)<<endl;
		v.clear();
	}
	return 0;
}
const int N = 5e5+10, mod = 998244353, len = 6100;

void add(int &a, LL b){a = (a+b)%mod;return ;}

int dp[3100][12200], co[N], color, n, siz[N], num[N], c[12200], de[N];
vector<int> v[N];
int ans = 0;

// c 辅助数组  co[i] i的颜色   len = 6000负数变正数  siz[i] i的子树大小  num[i] i 
void dfs(int u, int fa)  
{
	for(int i = len-num[color-1];i <= len+num[color-1];i ++) dp[u][i] = c[i] = 0;
	dp[u][(co[u] == color ? 1 : -1)+len] = 1; 
	de[u] = co[u] == color;
	siz[u] = 1;
	for(auto x : v[u])
	{
		if(x == fa) continue;
		dfs(x, u);
		for(int i = len-num[color];i <= num[color] + len;i ++) c[i] = dp[u][i];
		
		int up = de[u], down = min(num[color], siz[u]-de[u]);
		
		for(int i = len-down;i <= len+up;i ++)  
			for(int j = -min(siz[x]-de[x], num[color]);j <= de[x];j ++)
				add(dp[u][i+j], 1LL*c[i]*dp[x][len+j]);   
		siz[u] += siz[x];de[u] += de[x];  // 好像是 可以 防止一条链 ,这样上面就要是i+j = i + j 
	}

	for(int i = len+1;i <= num[color]+len;i ++) add(ans, dp[u][i]);
}

int main() 
{
	scanf("%d", &n);
	for(int i = 1;i <= n;i ++) scanf("%d", co+i), num[co[i]] ++;
	for(int i  =2;i <= n;i ++) {
		int a, b;
		scanf("%d%d", &a, &b);
		v[a].push_back(b);
		v[b].push_back(a);
	}
	for(int i = 1;i <= n;i ++)
		color = i, dfs(1, 0);
	cout<<ans<<endl;

	return 0;
}
int h[N];
vector<int> v[N];
LL cost[N];

void dfs(int u, int fa) 
{
	int t = 0;
	for(auto x : v[u])
	{
		if(x == fa) continue;
		dfs(x, u);
		t = max(t, h[x]);
		cost[u] += cost[x];
	}	
	if(t < h[u]) cost[u] += h[u] - t;
	else h[u] = t;	
//	cout<<u<<' '<<h[u]<<' '<<cost[u]<<' '<<t<<endl;
	return ;	
}

int main() 
{
	int n, pos = 1;
	scanf("%d", &n);
	for(int i = 1;i <= n;i ++) scanf("%d", h+i), pos = h[pos] < h[i] ? i : pos;
	for(int i = 2;i <= n;i ++)
	{
		int a, b;
		scanf("%d%d", &a, &b);
		v[a].push_back(b); v[b].push_back(a);
	}
	LL z = 0;
	vector<int> ans; ans.clear(); ans.push_back(0);
	for(auto x : v[pos])
		dfs(x, pos), ans.push_back(h[x]), z += cost[x];
	sort(ans.begin(), ans.end(), greater<int>());
//	cout<<h[3]<<' '<<cost[3]<<endl;
	z += max(h[pos]-ans[1], 0) + max(h[pos] - ans[0], 0);
	cout<<z<<endl;
	return 0;
}

t<=3说明只能得到一个子树或者另一颗子树的根节点,然后分类成三种树

LL dp[3][N];
int a[N], t[N];
vector<int> v[N];

void dfs(int u, int fa)
{
	int ma = 0;
	PII c[3] = {{1e18, 0}, {1e18, 0}}; // 求dp[2][x] -  
	for(auto x : v[u])
	{
		if(x == fa) continue;
		dfs(x, u);
		dp[2][u] += dp[1][x]; ma = max(ma, a[x]);
		c[2] = {dp[1][x]-dp[2][x], x}; sort(c, c+3);
	}
	dp[1][u] = dp[2][u] + ma;

	for(auto x : v[u])
	{
		if(x == fa || t[x] < 3) continue;
		dp[1][u] = max(dp[1][u], dp[2][u] + dp[0][x] - dp[1][x] - c[c[0].second == x].first);
	}	
	dp[2][u] += a[u];
	dp[0][u] = dp[1][u] + a[u];
}

int main() 
{
	int _;
	scanf("%d", &_);
	while(_ --)
	{
		int n;
		scanf("%d", &n);
		for(int i = 1;i <= n;i ++) scanf("%d", a+i);
		for(int i = 1;i <= n;i ++) scanf("%d", t+i); 
		for(int i = 2;i <= n;i ++)
		{
			int a, b;
			scanf("%d%d", &a, &b);
			v[a].push_back(b);
			v[b].push_back(a); 
		}
		dfs(1, 0);
		printf("%lld\n", dp[0][1]);
		for(int i = 1;i <= n;i ++) dp[0][i] = dp[1][i] = dp[2][i] = 0, v[i].clear();
	}
	return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李昌荣。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值