CCF NOIP 2021模拟 10.18

CCF NOIP 2021模拟 10.18

T1

problem

米娅有n​个寻宝的地区,在第i​个地区寻宝可以带来ai​的快乐值,每次米娅会随机选择一个还没有的搜寻过的地区进行寻宝,搜寻第i​个地区(i​还没有搜寻过)的概率为ai∑j,j还未被搜寻过(包括i)aj​,搜寻后会得到ai​的快乐值
由于某种原因,米娅搜寻了一号地区后就会停止,米娅想知道她可以获得的快乐值的期望
由于loopers​只在一天不断轮回,所以米娅只想知道这个数在mod 109+7​意义下的值
【输入格式】
从loopers.in中读入数据
第一行输入一个整数n
第二行输入n个整数a1,a2,…,an
【输出格式】
输出一个整数表示期望的快乐对109+7取模后的结果
【样例一】
输入
4
1 2 3 4
输出
983333348
样例解释
答案为46760
【数据范围与约定】
对于100%的数据,保证1≤n≤107,1≤ai≤5∗107
测试点编号 n ai
1-3 ≤20​ ≤5∗107​
4-5 ≤107​ =1​
6-8 ≤1∗105​ ≤5∗107
9-10 ≤107 ≤5∗107
注:由于输入规模较大,建议使用读入优化

那个题贴上去概率方程显示不出来我也不会弄,就这样吧,求教。

题解

还是蛮简单,考虑每个点的贡献,就是 a [ i ] × a [ i ] a [ 1 ] + a [ i ] a[i]\times\frac{a[i]}{a[1]+a[i]} a[i]×a[1]+a[i]a[i] ,考虑每个点要么1在它之前要么它先选,证明的话当这两个存在不管任何情况两个的概率比值都是这个。当然需要一个优化,不然复杂度 O ( n l o g v ) O(nlogv) O(nlogv)。类似于技巧吧,先求出 ∑ i = 1 n ( a [ 1 ] + a [ i ] ) \sum_{i=1}^{n}(a[1]+a[i]) i=1n(a[1]+a[i])的逆元和前缀后缀积就可以 O ( n ) O(n) O(n)算了。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

const int N=1e7+10,A=5e7+10;
int n,a[N]; LL sum=1,pre[N],aft[N],ans;
namespace modular{
	const LL mod=1e9+7;
	inline LL add(const LL a,const LL b){
		return a<mod-b?a+b:a-mod+b;
	}
	inline LL dec(const LL a,const LL b){
		return a<b?a-b+mod:a-b;
	}
	inline LL mul(const LL a,const LL b){
		return a*b%mod;
	}
	inline void Add(LL &a,const LL b){
		a=a<mod-b?a+b:a-mod+b;
	}
	inline void Dec(LL &a,const LL b){
		a=a<b?a-b+mod:a-b;
	}
	inline void Mul(LL &a,const LL b){
		a=a*b%mod;
	}
	inline LL ksm(LL a,LL p){
		LL res;
		for(res=1;p;Mul(a,a),p>>=1)
			(p&1)&&(Mul(res,a),1);
		return res;
	}
	inline LL Inv(const LL a){
		return ksm(a,mod-2);
	}
	inline void Min(LL &a,const LL b){
		a=min(a,b);
	}
	inline void Max(LL &a,const LL b){
		a=max(a,b);
	}
};
using namespace modular;

#define in read()
const int Mxdt=100000; 
inline char gc(){
	static char buf[Mxdt],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,Mxdt,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
	int t=0,f=0;char v=gc();
	while(v<'0')f|=(v=='-'),v=gc();
	while(v>='0')t=(t<<3)+(t<<1)+v-48,v=gc();
	return f?-t:t;
}
int main(){ 
//	freopen("loopers.in","r",stdin),freopen("loopers.out","w",stdout);
	n=in; for(int i=1;i<=n;i++) a[i]=in,Mul(sum,a[1]+a[i]); sum=Inv(sum);
	pre[0]=aft[n+1]=1; for(int i=1;i<=n;i++) pre[i]=mul(pre[i-1],a[1]+a[i]); for(int i=n;i>=1;i--) aft[i]=mul(aft[i+1],a[1]+a[i]);
	ans=a[1]; for(int i=2;i<=n;i++) Add(ans,mul(mul(a[i],a[i]),mul(sum,mul(pre[i-1],aft[i+1])))); printf("%lld\n",ans);

	return 0;
}

T2

problem

rewrite
描述
纵使新月的微光、明灭的星辰、街头的灯火全然散尽
纵使黑暗吞噬一切,我仍不会离你而去
篝酱正在进行对生命理论的研究
篝酱有一个正整数k
这些理论可以看做一个长度为n​的序列​
篝酱打算给每个理论一个[1,k]中的整数pi来评估这些理论
序列中某些理论是已经被研究过了,评估的数也是确定的
剩下的还被研究的pi可能取[1,k]​​中的任一整数
某些理论是由关联的,如果两个理论i,j满足ipj,则这一对理论会产生关联
由于生命理论是关乎整个地球大事
所以篝酱想知道所有理论间最多可能有多少对理论会产生关联
【输入格式】
从rewrite.in中读入数据
第一行两个整数 n,k​​​​ 意义
接下来一行 n​​ 个整数,第 i​ 个数表示pi​,每个数为 [0,k]​​ 中的一个整数,其中 0​​​ ​表示这个理论还未被研究
【输出格式】
输出一个正整数表示最多可能的关联个数
输出一个整数表示最大的逆序对数量
【样例一】
输入
6 6
5 0 1 4 0 6
输出
7
样例解释
一种方案是将序列填为5 5 1 4 1 6,可以得出此时逆序对数为7且没有更多逆序对的情况
【样例二】
输入
11 9
9 0 3 0 0 4 7 1 0 2 0
输出
44
【数据范围与约定】
对于100%的数据,保证1≤n≤200000,1≤k≤100,0≤pi≤k
测试点编号 n k​ 特殊限制
1 ≤8​ ≤8​
2 ≤2∗105 ≤100 保证没有位置为 0
3 ≤2∗105 ≤100 保证只有一个位置为0
4-5 ≤2∗105 ≤100 保证所有位置都为 0
6-7 ≤800​ ≤80​
8-10 ≤2∗105 ≤100

本机过了交上去全RE。最后找了几天,原因在于数组刚好开炸了,数组刚好开大了,好像510多MB,报错也就报成RE了(我不懂),所以把#define int long long改一下或者优化一下空间就能过了。确实应该算一下空间:三个大数组 ( 2 e 5 + 10 ) × 110 × 3 × 8 ÷ 1024 ÷ 1024 ≈ 503.56 (2e5+10)\times110\times3\times8{\div} 1024{\div} 1024\approx 503.56 (2e5+10)×110×3×8÷1024÷1024503.56,在加那么多个小数组程序运行空间确实炸了。数组已经开到 1 e 7 1e7 1e7了确实应该算一下。

题解

我不打算多说,挺恶心的,原来的和加的分开统计,外围枚举第二维,中间斜率优化 O ( n ) O(n) O(n)算,复杂度 O ( n k ) O(nk) O(nk)

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

#define int long long
const int N=2e5+10,A=110;
int n,k,a[N],num[N],cnt[N],pre[N][A],aft[N][A],hv[N][A],f[N],g[N],ans;
int q[N],l,r;

inline int X(const int i){
	return num[i];
}
inline int Y(const int i,const int t){
	return -g[i]+num[i]*num[i]+hv[i][t];
}
inline int K(const int i){
	return num[i];
}
inline double calc(const int j,const int i,const int t){
	return (double)(Y(i,t)-Y(j,t))/(1.0*(X(i)-X(j)));	
}
#define in read()
inline int read(){
	int f=1,k=0; char cp=getchar();
	while(cp!='-'&&(cp<'0'||cp>'9')) cp=getchar();
	if(cp=='-') f=-1,cp=getchar();
	while(cp>='0'&&cp<='9') k=(k<<3)+(k<<1)+cp-48,cp=getchar();
	return f*k;
}
signed main(){ 
//	freopen("rewrite.in","r",stdin),freopen("rewrite.out","w",stdout);
	n=in,k=in; for(int i=1;i<=n;i++) a[n-i+1]=in; for(int i=1;i<=n;i++) num[i]=num[i-1]+(a[i]==0);
	memset(cnt,0,sizeof(cnt)); for(int i=1;i<=n;i++){ for(int j=1;j<=k;j++) pre[i][j]=pre[i][j-1]+cnt[j]; if(a[i]) ++cnt[a[i]]; } //第i位之前小于等于j的个数 	
	memset(cnt,0,sizeof(cnt)); for(int i=n;i>=1;i--){ for(int j=k;j>=1;j--) aft[i][j]=aft[i][j+1]+cnt[j]; if(a[i]) ++cnt[a[i]]; } //第i位之后大于等于j的个数 
	for(int i=1;i<=n;i++) if(!a[i]) for(int j=1;j<=k;j++) hv[i][j]=hv[i-1][j]+pre[i][j-1]+aft[i][j+1]; else memcpy(hv[i],hv[i-1],sizeof(hv[i]));
	for(int i=1;i<=n;i++) if(a[i]) ans+=pre[i][a[i]-1];
	for(int t=1;t<=k;t++){ l=r=1; 
		for(int i=1;i<=n;i++){
			if(!a[i]){
				while(l<=r&&calc(q[l],q[l+1],t)<K(i)) ++l;
				f[i]=K(i)*X(q[l])-Y(q[l],t)+hv[i][t];
				while(l<=r&&calc(q[r-1],q[r],t)>calc(q[r],i,t)) --r; q[++r]=i;
			}
			else f[i]=f[i-1];
		} for(int i=1;i<=n;i++) g[i]=max(g[i],f[i]);
	} printf("%lld\n",ans+g[n]); 

	return 0;	
}

T3

problem

#5124 【2021.10.18NOIP测试】pockets
描述
眼前这个少女的笑容,和她这副喃喃自语的样子,仿佛与我记忆深处的某个东西产生了共鸣。
月光洒落在少女的侧脸上,居然让我感到一种几乎要落泪的怀念感。
那一定是……
白羽正在做炒饭
总共n盘炒饭排成一行,每盘炒饭有一个美味程度Ai
白羽会不断加工炒饭,每次白羽会选择一段区间[l,r]的炒饭和一个整数k,使得Ai​变成(Ai+k)%p​​
其中p​​是一个给定的整数
同时为了掌握炒饭的情况,白羽还想知道某两段炒饭美味程度是否依次相等
由于白羽想去吃西瓜棒冰,所以她希望你来帮助她
具体的,白羽希望要求你处理q次以下两种操作:
1 l r k​:白羽将Al,Al+1,…Ar​变成(Al+k)%p,(Al+1+k)%p,…(Ar+k)%p​
2 l r L​​​:白羽想知道Al,Al+1,…Al+L−1​​​与Ar,Ar+1,…Ar+L−1​​​是否相同
【输入格式】
从pockets.in中读入数据
第一行输入三个整数n,q,p
第二行输入n个整数表示初始炒饭的美味程度的A
接下来q行每行输入四个整数op,l,r,k​表示如上的操作
【输出格式】
对于白羽每次op=2​的询问,输出一行 ye5​ 或者 n0​ 表示相同或者不同
【样例一】
输入
8 9 3
0 1 1 0 1 2 2 1
2 1 4 2
1 4 8 2
2 2 5 3
1 7 7 1
2 2 5 3
1 1 7 1
2 1 5 4
1 7 7 2
2 1 5 4
输出
ye5
n0
n0
n0
ye5
【数据范围与约定】
对于100%​​的数据,保证$1\le n,q\le 500000,2\le p\le 65536,0\le A_i
且对于每次操作,$1\le l\le r\le n,\le k
测试点编号 n,q 特殊限制
T1:1-2 ≤5000
T2:3-4 ≤105​ 操作2的次数≤100
T3:5-7 ≤80000​ p=2
T4:8-9 ≤105 操作1的次数≤100
T5:10-12 ≤105 n,q≤100000,p=65536,每次操作1中k=1
T6:13-16 ≤105 n,q≤100000
T7:17-20 ≤5∗105
注:上面的T只是一个为了方便对应题解部分分的数据类别标号,与题目无实际联系

跑了个样例就走了,没有发数据呀 ,最后AC码变RE,线段树少判个边界,记住要多考虑一下范围吧,线段树经常犯这种问题。

题解

先说一件事,线段树不能维护区间取模、开根与区间加操作,两个操作都只能不带修改保证 l o g log log。应该要用hash,先说部分分,如果没有取模可以区间hash值直接加维护就好了,取模记区间最大暴力修改超过模数的。满分就考虑维护差分,两个区间检查就是起点区间和是否为0且区间内hash相同。dalao他们质疑正确性,我也挺蒙,考虑:差分数字和区间和计算都保证在模数范围内,都是唯一固定的,知道这些推且只能推一个序列,保证了维护一定是正确的,并没有问题。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

#define int long long
#define pii pair<int,int>
#define fi first
#define se second
const int N=5e5+10,T=N<<2,H1=3777,P1=1000003,H2=4111,P2=1000007;
int n,m,M,opt,x,y,l,c[N],a[N],pw1[N],pw2[N];	

#define lp (p<<1)
#define rp (p<<1|1)
#define mid ((pl[p]+pr[p])>>1)
int rt,pl[T],pr[T],sum[T],h1[T],h2[T];
inline void pushup(const int p){
	sum[p]=((sum[lp]+sum[rp])%M+M)%M;
	h1[p]=(((h1[lp]*pw1[pr[p]-mid])%P1+P1)%P1+h1[rp]+P1)%P1;
	h2[p]=(((h2[lp]*pw2[pr[p]-mid])%P2+P2)%P2+h2[rp]+P2)%P2;
}
inline void build(const int l,const int r,const int p=rt){
	pl[p]=l,pr[p]=r; if(pl[p]==pr[p]) return sum[p]=h1[p]=h2[p]=a[l],void();
	build(l,mid,lp),build(mid+1,r,rp); pushup(p);
}
inline void update(const int x,const int v,const int p=rt){
	if(x>n) return;
	if(pl[p]==pr[p]) return sum[p]=h1[p]=h2[p]=((sum[p]+v)%M+M)%M,void();
	update(x,v,x<=mid?lp:rp); pushup(p);
}
inline int query(const int x,const int y,const int p=rt){
	if(x>y) return 0;
	if(x==pl[p]&&y==pr[p]) return sum[p];
	if(y<=mid) return query(x,y,lp); if(x>mid) return query(x,y,rp);
	return ((query(x,mid,lp)+query(mid+1,y,rp))%M+M)%M;
}
inline pii H(const int x,const int y,const int p=rt){
	if(y<x) return make_pair(0,0);
	if(x==pl[p]&&y==pr[p]) return make_pair(h1[p],h2[p]);
	if(y<=mid) return H(x,y,lp); if(x>mid) return H(x,y,rp);
	pii h=H(x,mid,lp),hh=H(mid+1,y,rp); 
	return make_pair((((h.fi*pw1[y-mid])%P1+P1)%P1+hh.fi+P1)%P1,(((h.se*pw2[y-mid])%P2+P2)%P2+hh.se+P2)%P2);
}

#define in read()
inline int read(){
	int f=1,k=0; char cp=getchar();
	while(cp!='-'&&(cp<'0'||cp>'9')) cp=getchar();
	if(cp=='-') f=-1,cp=getchar();
	while(cp>='0'&&cp<='9') k=(k<<3)+(k<<1)+cp-48,cp=getchar();
	return f*k;
}
signed main(){ 
//	freopen("pockets.in","r",stdin),freopen("pockets.out","w",stdout);
	n=in,m=in,M=in; for(int i=1;i<=n;i++) c[i]=in,a[i]=((c[i]-c[i-1])%M+M)%M; 
	pw1[0]=pw2[0]=1; for(int i=1;i<=n;i++) pw1[i]=(pw1[i-1]*H1)%P1,pw2[i]=(pw2[i-1]*H2)%P2; build(1,n,rt=1);
	while(m--){ opt=in,x=in,y=in,l=in;
		if(opt==1) update(x,l),update(y+1,-l);
		else if(query(x+1,y)==0&&H(x+1,x+l-1)==H(y+1,y+l-1)) puts("ye5"); else puts("n0");
	}

	return 0;
}

质数 啥乱设的,不知道是不是质数。。。考试忘打query边界了。。。

T4

problem

dohnadohna
描述
一起来干坏事吧
阿熊一行人正在夺拿人材
具体的,这个地图可以看做由n个点m​条有向路径组成,而且这个地图不存在环,即构成了一个有向无环图(DAG)
阿熊一行人从1号点出发,到n号点逃出
每个点都有一个人材,第i个点的人材有ai的负担,bi​的价值
每当阿熊一行人经过某个节点的时候,可以选择是否夺拿该点的人材
由于为了避免停留过久引发亚总义的追捕,所以他们夺拿的人材负担之和要≤k
阿熊想知道他们最多可以夺拿的人材价值之和为多少,以及有多少种方案可以夺拿这么多的价值
除此之外,阿熊担心亚总义可能会在某个节点设有埋伏,则他们不能经过这个点
因为并不知道哪个点可能设有埋伏,所以他还想知道对每个点知道如果这个点设有埋伏
那么他们可以夺拿的最大价值和方案数
由于方案可能会很多,所以阿熊只想知道方案数对109+7取模后的结果
如果不经过某个点的时候无法到n号点逃出,则输出−1
【输入格式】
从 dohnadohna.in读入
第一行三个整数n,m,k​,表示点数,边数和容量​
接下来n行每行两个整数表示ai,bi,表示人材的属性​
接下来m行每行两个整数u,v,表示u到v有一条有向路径
【输出格式】
输出到 dohnadohna.out​
输出 n+1​ 行,每行两个数
第一行表示不考虑有埋伏的答案
接下来n行表示i号点有埋伏时的答案
【样例一】
输入
4 5 5
1 2
2 3
3 4
4 2
1 2
1 3
2 4
3 4
1 4
输出
6 1
-1
6 1
5 1
-1
【样例二】
输入
8 14 15
2 5
2 7
1 9
5 10
7 6
7 7
15 6
1 5
2 3
3 4
2 5
2 6
4 7
7 8
1 8
1 2
1 3
1 2
1 3
1 4
1 5
1 4
输出
36 2
-1
29 2
20 2
10 1
36 2
36 2
10 1
-1
【数据范围与约定】
对于 100% 的数据,满足1≤n≤105,1≤m≤5∗105,1≤k≤100,1≤ai≤k,1≤bi≤1000
保证初始图联通,经过连接相同两个点的不同边视作不同的方案
测试点编号 n m 特殊限制
1 ≤8 ≤20
2-3 ≤500 ≤2000
4-5 ≤105 ≤5∗105 保证删去除1,n外所有点得到的的最大价值相等
6-10 ≤105 ≤5∗105

是个神仙题,我用最后的10分钟拿到了10分暴力。

题解

先说一下部分分吧,正解拓扑序没怎么搞懂。
10分:每个点重新暴搜(5分钟看题,5分钟码完)
30分:暴搜改成拓扑排序做背包 O ( n m k ) O(nmk) O(nmk)
50分:最大值不变,方案改变,就是减去经过该点的方案,这个dp维护个从1-它和它-n的方案直接统计即可 O ( m k + n k ) O(mk+nk) O(mk+nk)
100分:考虑一个点被删后哪些路径仍会造成贡献。结论:算出每个点的拓扑序(就是拓扑排序的顺序),每个边的贡献就是dfn[x]+1到dfn[y]-1的所有点,就是说这些点都被这条边“越过”了,考虑dfn不连续是因为中间没拓扑完,也就是越过的意思。线段树维护区间修改该边的贡献,边是dp重载运算符计算,最后dfs一遍线段树做出答案。复杂度 O ( m k + m l o g n + n l o g n ) O(mk+mlogn+nlogn) O(mk+mlogn+nlogn)

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
namespace modular{
	const LL mod=1e9+7;
	inline LL add(const LL a,const LL b){
		return a<mod-b?a+b:a-mod+b;
	}
	inline LL dec(const LL a,const LL b){
		return a<b?a-b+mod:a-b;
	}
	inline LL mul(const LL a,const LL b){
		return a*b%mod;
	}
	inline void Add(LL &a,const LL b){
		a=a<mod-b?a+b:a-mod+b;
	}
	inline void Dec(LL &a,const LL b){
		a=a<b?a-b+mod:a-b;
	}
	inline void Mul(LL &a,const LL b){
		a=a*b%mod;
	}
	inline LL ksm(LL a,LL p){
		LL res;
		for(res=1;p;Mul(a,a),p>>=1)
			(p&1)&&(Mul(res,a),1);
		return res;
	}
	inline LL Inv(const LL a){
		return ksm(a,mod-2);
	}
	inline void Min(LL &a,const LL b){
		a=min(a,b);
	}
	inline void Max(LL &a,const LL b){
		a=max(a,b);
	}
};
using namespace modular;

#define int long long
const int N=1e5+10,T=N<<2,K=110;
vector<int> e[N],pre[N]; int du[N];
int n,m,k,x,y,w[N],v[N],dfn[N],idd[N],dfnn;
struct Node{
	int v,num; //价值,方案数 
	Node(const int _v=-1,const int _num=0){
		v=_v,num=_num;
	}
	inline void update(const Node &y){
		if(v<y.v) v=y.v,num=y.num;
		else if(v==y.v) Add(num,y.num);
	}
	friend inline Node operator + (const Node &x,const Node &y){
		return Node{x.v+y.v,mul(x.num,y.num)};
	}
	friend inline Node operator + (const Node &x,const int y){
		return Node{x.v+y,x.num};
	}
}f[N][K],g[N][K],ans[N];

#define lp (p<<1)
#define rp (p<<1|1)
#define mid ((pl[p]+pr[p])>>1)
int rt,pl[T],pr[T]; Node t[T];
inline void build(const int l,const int r,const int p=rt){
	pl[p]=l,pr[p]=r,t[p]=Node(); if(pl[p]==pr[p]) return;
	build(l,mid,lp),build(mid+1,r,rp);
}
inline void pushdown(const int p){
	t[lp].update(t[p]),t[rp].update(t[p]);
}
inline void update(const int x,const int y,const Node &up,const int p=rt){
	if(x==pl[p]&&y==pr[p]) return t[p].update(up);
	if(y<=mid) update(x,y,up,lp); else if(x>mid) update(x,y,up,rp);
	else update(x,mid,up,lp),update(mid+1,y,up,rp);
}
inline void get(const int p=rt){
	if(pl[p]==pr[p]) return ans[idd[pl[p]]]=t[p],void();
	pushdown(p); get(lp),get(rp);
}

#define in read()
inline int read(){
	int f=1,k=0; char cp=getchar();
	while(cp!='-'&&(cp<'0'||cp>'9')) cp=getchar();
	if(cp=='-') f=-1,cp=getchar();
	while(cp>='0'&&cp<='9') k=(k<<3)+(k<<1)+cp-48,cp=getchar();
	return f*k;
}
signed main(){
	n=in,m=in,k=in; for(int i=1;i<=n;i++) w[i]=in,v[i]=in; 
	while(m--) x=in,y=in,e[x].push_back(y),pre[y].push_back(x),++du[y];
	queue<int> q; for(int i=1;i<=n;i++) if(!du[i]) q.push(i),idd[dfn[i]=++dfnn]=i;
	while(!q.empty()){ int p=q.front(); q.pop();
		for(int to:e[p]){ --du[to]; if(!du[to]) q.push(to),idd[dfn[to]=++dfnn]=to; }
	}
	for(int i=1;i<=n;i++){ int p=idd[i];
		if(p==1) f[p][0]=Node{0,1},f[p][w[p]]=Node{v[p],1};
		for(int fa:pre[p]) for(int j=0;j<=k;j++) if(~f[fa][j].v){
			f[p][j].update(f[fa][j]);
			if(j+w[p]<=k) f[p][j+w[p]].update(f[fa][j]+v[p]);
		}
	}
	for(int i=n;i>=1;i--){ int p=idd[i];
		if(p==n) g[p][0]=Node{0,1},g[p][w[p]]=Node{v[p],1};
		for(int fa:e[p]) for(int j=0;j<=k;j++) if(~g[fa][j].v){
			g[p][j].update(g[fa][j]);
			if(j+w[p]<=k) g[p][j+w[p]].update(g[fa][j]+v[p]);
		}
	}
	for(int i=1;i<=n;i++) for(int j=1;j<=k;j++) f[i][j].update(f[i][j-1]);
	build(1,n,rt=1); for(int u=1;u<=n;u++) for(int v:e[u]) if(dfn[u]+1<=dfn[v]-1){
		Node mxx; for(int j=0;j<=k;j++) if(~f[u][j].v&&~g[v][k-j].v) mxx.update(f[u][j]+g[v][k-j]);
		update(dfn[u]+1,dfn[v]-1,mxx);
	}
	if(dfn[1]>1) update(1,dfn[1]-1,f[n][k]); if(dfn[n]<n) update(dfn[n]+1,n,f[n][k]);
	if(f[n][k].v==-1) puts("-1"); else printf("%lld %lld\n",f[n][k].v,f[n][k].num); get();
	for(int i=1;i<=n;i++) if(ans[i].v==-1) puts("-1"); else printf("%lld %lld\n",ans[i].v,ans[i].num);

	return 0;
}

预计310实测90。 有什么地方也错了欢迎指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值