noip模拟46[偏僻]

noip模拟46 solutions

又一次的失败,败的挺惨的

思路全都哦不靠边,我根本想不到,不知道是见过的题太少了,还是能力真的有问题

我期待每一次考试,同样期待每一次成绩

算啦,反正我改出来了,不在乎之前考得咋样了,每次努力就行啦

T1 数数

这是个打卡题,然后我就只有50pts,话说为什么,因为我傻了

我看到这个题就一直在往dp上想,然后搞出来一个\(\mathcal{O(n^3)}\)的dp

就完蛋了,我还美滋滋的,以为他们都做不出来,考完之后一看AC30

50pts
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=2005;
int n,a[N];
ll dp[N];
signed main(){
	scanf("%d",&n);
	for(re i=1;i<=n;i++)scanf("%d",&a[i]);
	sort(a+1,a+n+1);
	for(re k=1;k<=n;k++){
		memset(dp,0,sizeof(dp));
		for(re i=1;i<=n;i++){
			if(i<=k)dp[i]=dp[i-1]+1ll*(2*i-k-1)*a[i];
			for(re j=min(i-1,k);j>=1;j--){
				dp[j]=max(dp[j],dp[j-1]+1ll*(2*j-k-1)*a[i]);
			}
		}
		printf("%lld\n",dp[k]);
	}
}

然后就想想贪心就行了,先排个序,就可以直接把式子化简一下就好了

设当前点在选出来的点里排名第j位,那么最后的答案就是

\[\sum\limits^{k}_{j=1}(2*j-k-1)*a[i] \]

那么我们要找的就是前\(\frac{k}{2}\)个最小的,后\(\frac{k}{2}\)个最大的

我们已经找到了这个贪心策略,直接贪就行了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=300005;
int n,a[N];
ll sum,ans,i1,i2;
signed main(){
	scanf("%d",&n);
	for(re i=1;i<=n;i++)scanf("%d",&a[i]);
	sort(a+1,a+n+1);
	i1=1;i2=n;
	for(re k=1;k<=n;k++){
		if(k&1)ans+=sum;
		else sum+=a[i2]-a[i1],ans+=sum,++i1,--i2;
		printf("%lld\n",ans);
	}
}

T2 数树

这个难啊,我就是一点思路都没有,然后啥也不会做啦

好像题解上说这个题是简单的插头dp,我是真的不会,然后几乎把他弃掉了

后来zxb拯救了我,一个背包dp,弄得我还挺明白

首先统计合法方案肯定是不行的,因为要限制的条件过于苛刻,

只能容斥吧,但是容斥系数这个东西确实很难搞,我也不知道这个题的容斥系数是怎么出来的

对于一个容斥来说,我们要计算的一定是一个方案数,那么我们最后加入容斥方程的一定是最后的方案数,

我们设求出来s[i]表示至少有i个不合法的边的时候的方案数,

这个方案数并不是总方案数,这个只是选出i条不合法的边,如何去选的方案数

然后我们还需要向每个点上去填数,因为有i个边选了,所以我们可选择的点的数量会减少i

因为一个端点确定了,另外一个端点也就确定了,

总方案数就是\((n-i)!s[i]\),然后我们就多步容斥,具体多步容斥的+-我没有推出来

但是这个可以直接套二项式反演的式子,因为,这个也是至少问题,并且只是换了个系数而已

那么我们现在的问题就是求s[i],这个东西不可以直接用组合数的,因为在两条边拥有同一个终点或者同一个起点的时候,是不合法的

我们只能dp吧,反正也是在树上,应该很好转移的,就是树上的背包

设dct[i][j][0/1/2/3]表示在i节点,有j条边被选了

0表示当前节点连的边一条也没有选

1表示当前节点连了一条入边

2表示有一条出边

3表示出边入边各有一条,那么转移的时候就直接从子树向上转移就行了

注意要考虑两条边不能同起点或同终点的限制

最后容斥一下就好了,s[i]即为dct[1][i][0/1/2/3]

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define int long long
const int N=5005;
const int mod=998244353;
int n,ans;
int jk[N],dct[N][N][4],smw[N][4];
int to[N*2],nxt[N*2],head[N],typ[N*2],rp;
int siz[N];
void add_edg(int x,int y,int z){
	to[++rp]=y;
	typ[rp]=z;
	nxt[rp]=head[x];
	head[x]=rp;
}
void dfs(int x,int f){
	dct[x][0][0]=1;
	for(re i=head[x];i;i=nxt[i]){
		int y=to[i];
		if(y==f)continue;
		dfs(y,x);memset(smw,0,sizeof(smw));
		for(re j=0;j<=siz[x];j++){
			for(re k=0;k<=siz[y];k++){
				int sum=0;
				for(re o=0;o<4;o++)sum=(sum+dct[y][k][o])%mod;
				for(re o=0;o<4;o++)smw[j+k][o]=(smw[j+k][o]+sum*dct[x][j][o])%mod;
				if(!typ[i]){
					smw[j+k+1][1]=(smw[j+k+1][1]+dct[x][j][0]*(dct[y][k][0]+dct[y][k][1]))%mod;
					smw[j+k+1][3]=(smw[j+k+1][3]+dct[x][j][2]*(dct[y][k][0]+dct[y][k][1]))%mod;
				}
				else{
					smw[j+k+1][2]=(smw[j+k+1][2]+dct[x][j][0]*(dct[y][k][0]+dct[y][k][2]))%mod;
					smw[j+k+1][3]=(smw[j+k+1][3]+dct[x][j][1]*(dct[y][k][0]+dct[y][k][2]))%mod;
				}
			}
		}
		siz[x]+=siz[y];
		for(re j=0;j<=siz[x];j++)
			for(re k=0;k<4;k++)
				dct[x][j][k]=smw[j][k];
	}
	siz[x]+=1;
}
signed main(){
	scanf("%lld",&n);jk[0]=1;
	for(re i=1;i<n;i++){
		int x,y;scanf("%lld%lld",&x,&y);
		add_edg(x,y,1);add_edg(y,x,0);
		jk[i]=jk[i-1]*i%mod;
	}
	jk[n]=jk[n-1]*n%mod;
	dfs(1,0);int sum=0;
	for(re i=0,bas=1;i<n;i++,bas=-bas){
		sum=0;
		for(re j=0;j<4;j++)sum=(sum+dct[1][i][j])%mod;
		ans=(ans+bas*jk[n-i]%mod*sum%mod+mod)%mod;
	}
	printf("%lld",ans);
}

T3 鼠树

这个题我不想说啥了,因为思路极其简单,很早很早就打出来了,但是调了一下午+两晚上

最难的地方就是删除一个黑点了,我们用线段树吧他子树内的都加上他的值与他上面的黑点的值的差值

然后对他的子树,做4操作,把多加的减去就行了

还有找爹的操作,对深度维护set然后,动态添加和删除,每次提取set的begin就行了

不多不多也就两百来行

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ui unsigned int
const int N=3e5+5;
const int M=5e5+5;
int n,m;
int fa[N],to[N],nxt[N],head[N],rp;
void add_edg(int x,int y){
	to[++rp]=y;
	nxt[rp]=head[x];
	head[x]=rp;
}
int siz[N],son[N],dep[N];
void dfs_fi(int x){
	siz[x]=1;son[x]=0;
	for(re i=head[x];i;i=nxt[i]){
		int y=to[i];
		dep[y]=dep[x]+1;
		dfs_fi(y);
		siz[x]+=siz[y];
		if(!son[x]||siz[y]>siz[son[x]])son[x]=y;
	}
}
int dfn[N],dfm[N],cnt,idf[N],top[N];
void dfs_se(int x,int f){
	top[x]=f;dfn[x]=++cnt;idf[cnt]=x;
	if(son[x])dfs_se(son[x],f);
	for(re i=head[x];i;i=nxt[i]){
		int y=to[i];
		if(y==son[x])continue;
		dfs_se(y,y);
	}
	dfm[x]=cnt;
}
struct comp{bool operator () (int x,int y){return dep[idf[x]]<dep[idf[y]];}}; 
set<int> st[N];
int find_belong(int x){
	int now=x;
	while(1){
		if(st[top[now]].begin()!=st[top[now]].end()&&dep[idf[*st[top[now]].begin()]]<=dep[now]){
			return idf[*--st[top[now]].upper_bound(dfn[now])];
		}
		now=fa[top[now]];
	}
}
struct XDS{
	#define ls x<<1
	#define rs x<<1|1
	ui sum[N*16],w[N*16],laz[N*16];
	int c[N*16];
	void pushup(int x){
		sum[x]=sum[ls]+sum[rs];
		c[x]=c[ls]+c[rs];
		return ;
	}
	void pushdown(int x){
		if(!laz[x])return ;
		if(c[ls])laz[ls]+=laz[x],w[ls]+=laz[x],sum[ls]+=1ll*laz[x]*c[ls];
		if(c[rs])laz[rs]+=laz[x],w[rs]+=laz[x],sum[rs]+=1ll*laz[x]*c[rs];
		laz[x]=0;return ;
	}
	void add_w(int x,int l,int r,int ql,int qr,ui v){
		if(ql<=l&&r<=qr){
			if(c[x]){
				sum[x]+=1ll*c[x]*v;laz[x]+=v;w[x]+=v;
			}
			return ;
		}
		pushdown(x);
		int mid=l+r>>1;
		if(ql<=mid)add_w(ls,l,mid,ql,qr,v);
		if(qr>mid) add_w(rs,mid+1,r,ql,qr,v);
		pushup(x);return ;
	}
	void add_c(int x,int l,int r,int pos,int v){
		if(l==r){
			c[x]+=v;sum[x]=c[x]*w[x];
			if(!c[x])w[x]=0;
			return ;
		}
		pushdown(x);
		int mid=l+r>>1;
		if(pos<=mid)add_c(ls,l,mid,pos,v);
		else add_c(rs,mid+1,r,pos,v);
		pushup(x);return ;
	}
	void ins_new(int x,int l,int r,int pos,int vc,ui vw){
		if(l==r){
			w[x]=vw;c[x]=vc;sum[x]=w[x]*c[x];
			return ;
		}
		pushdown(x);
		int mid=l+r>>1;
		if(pos<=mid)ins_new(ls,l,mid,pos,vc,vw);
		else ins_new(rs,mid+1,r,pos,vc,vw);
		pushup(x);return ;
	}
	int query_c(int x,int l,int r,int ql,int qr){
		if(ql<=l&&r<=qr)return c[x];
		pushdown(x);
		int mid=l+r>>1,ret=0;
		if(ql<=mid)ret+=query_c(ls,l,mid,ql,qr);
		if(qr>mid)ret+=query_c(rs,mid+1,r,ql,qr);
		pushup(x);return ret;
	}
	ui query_w(int x,int l,int r,int pos){
		if(l==r)return w[x];
		pushdown(x);
		int mid=l+r>>1;
		if(pos<=mid)return query_w(ls,l,mid,pos);
		else return query_w(rs,mid+1,r,pos);
	}
	ui query_sum(int x,int l,int r,int ql,int qr){
		if(ql<=l&&r<=qr)return sum[x];
		pushdown(x);
		int mid=l+r>>1;ui ret=0;
		if(ql<=mid)ret+=query_sum(ls,l,mid,ql,qr);
		if(qr>mid)ret+=query_sum(rs,mid+1,r,ql,qr);
		pushup(x);return ret;
	}
	#undef ls
	#undef rs
}xds;
ui ago[N];
struct DSU{
	#define ls x<<1
	#define rs x<<1|1
	ui tr[N*16],laz[N*16];
	void pushup(int x){
		tr[x]=tr[ls]+tr[rs];
		return ;
	}
	void pushdown(int x,int l,int r){
		if(!laz[x])return ;
		int mid=l+r>>1;
		ui rsz=r-mid,lsz=mid-l+1;
		tr[ls]+=laz[x]*(mid-l+1);
		tr[rs]+=laz[x]*(r-mid);
		laz[ls]+=laz[x];
		laz[rs]+=laz[x];
		laz[x]=0;
		return ;
	}
	void ins(int x,int l,int r,int ql,int qr,ui v){
		pushdown(x,l,r);
		if(ql<=l&&r<=qr){
			tr[x]+=(ui)(r-l+1)*v;
			laz[x]+=v;
			return ;
		}
		int mid=l+r>>1;
		if(ql<=mid)ins(ls,l,mid,ql,qr,v);
		if(qr>mid)ins(rs,mid+1,r,ql,qr,v);
		pushup(x);return ;
	}
	ui query(int x,int l,int r,int ql,int qr){
		pushdown(x,l,r);
		if(ql<=l&&r<=qr)return tr[x];
		int mid=l+r>>1;ui ret=0;
		if(ql<=mid)ret+=query(ls,l,mid,ql,qr);
		if(qr>mid)ret+=query(rs,mid+1,r,ql,qr);
		pushup(x);return ret;
	}
	#undef ls
	#undef rs
}dsu;
signed main(){
	scanf("%d%d",&n,&m);
	for(re i=2;i<=n;i++){
		scanf("%d",&fa[i]);
		add_edg(fa[i],i);
	}
	dfs_fi(1);dfs_se(1,1);
	st[1].insert(dfn[1]);
	xds.ins_new(1,1,n,dfn[1],n,0);
	while(m--){
		ui typ,k,w,sz,who,p,x,c;ui res,s;
		scanf("%u",&typ);
		switch(typ){
			case 1:
				scanf("%u",&k);s=k;
				printf("%u\n",xds.query_w(1,1,n,dfn[find_belong(k)])+dsu.query(1,1,n,dfn[k],dfn[k]));
				break;
			case 2:
				scanf("%u%u",&k,&w);s=k;
				xds.add_w(1,1,n,dfn[k],dfn[k],w);
				break;
			case 3:
				scanf("%u",&k);s=k;
				res=xds.query_sum(1,1,n,dfn[k],dfm[k]);
				res+=xds.query_w(1,1,n,dfn[find_belong(k)])*(siz[k]-xds.query_c(1,1,n,dfn[k],dfm[k]));
				res+=dsu.query(1,1,n,dfn[k],dfm[k]);
				printf("%u\n",res);
				break;
			case 4:
				scanf("%u%u",&k,&w);s=k;
				xds.add_w(1,1,n,dfn[k],dfm[k],w);
				break;
			case 5:
				scanf("%u",&k);s=k;
				sz=xds.query_c(1,1,n,dfn[k],dfm[k]);
				ago[k]=xds.query_w(1,1,n,dfn[find_belong(k)]);
				xds.ins_new(1,1,n,dfn[k],siz[k]-sz,ago[k]);
				xds.add_c(1,1,n,dfn[find_belong(k)],sz-siz[k]);
				st[top[k]].insert(dfn[k]);
				break;
			case 6:
				scanf("%u",&k);s=k;
				who=find_belong(fa[k]);
				p=xds.query_w(1,1,n,dfn[k]);
				x=xds.query_w(1,1,n,dfn[who]);
				dsu.ins(1,1,n,dfn[k],dfm[k],p-x);
				xds.add_w(1,1,n,dfn[k],dfm[k],x-p);
				c=xds.query_c(1,1,n,dfn[k],dfn[k]);
				xds.add_c(1,1,n,dfn[who],c);
				xds.add_c(1,1,n,dfn[k],-c);
				st[top[k]].erase(dfn[k]);
				break;
		}
	}
}

T4 ckw树

目前放弃状态

posted @ 2021-08-25 07:42  fengwu2005  阅读(94)  评论(0)    收藏  举报