noip模拟21[Median·Game·Park]

noip模拟21 solutions

这我也不知道咋了,考试就挺没欲望,看见啥题都只会打暴力,

然后就考挂了,

要有状态,集训的时候绝对不能松懈

T1 Median

这个题,他就有点傻逼,真的太傻逼了,\(O(nlogn)\)过不了\(O(n^2)\)能过

题解告诉我啥这些数据是伪随机的,分布极其均匀,所以中位数的变化是常数级的,所以\(O(n^2)\)\(O(n)\)???

正常的话,这个题可以用nth_element、各种平衡树、各种高级的STL都可以达到很小的复杂度,可是你比不过\(O(n^2)\)

真的,看到题解的时候我要气死了,就是存一个桶,因为有模数,然后记录一下中位数以及他的排名就好了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=1e7+5;
int n,k,w;
int prime[N],cnt;
bitset<N*18> vis;
int s1[N],s2[N];
double ans;
int now[N],sum[N*2];
signed main(){
	scanf("%d%d%d",&n,&k,&w);
	for(re i=2;cnt<=n;i++){
		if(!vis[i])prime[++cnt]=i;
		for(re j=1;j<=cnt&&prime[j]*i<=n*18;j++){
			vis[prime[j]*i]=1;
			if(i%prime[j]==0)break;
		}
	}
	for(re i=1;i<=n;i++)s1[i]=1ll*i*prime[i]%w;
	for(re i=1;i<=n;i++)s2[i]=s1[i]+s1[i/10+1];
	if(k&1){
		for(re i=1;i<=k;i++)sum[s2[i]]++,now[i]=s2[i];
		sort(now+1,now+k+1);
		int mid=now[k+1>>1],rak=0;
		for(re i=1;i<=k;i++)
			if(now[i]<=mid)rak++;
		ans+=mid;
		for(re i=2;i<=n-k+1;i++){
			if(s2[i-1]<=mid)rak--;
			if(s2[i+k-1]<=mid)rak++;
			sum[s2[i-1]]--;
			sum[s2[i+k-1]]++;
			while(rak-sum[mid]>=(k+1>>1))rak-=sum[mid],mid--;
			while(rak+sum[mid+1]<(k+1>>1))rak+=sum[mid+1],mid++;
			if(rak<(k+1>>1))mid++,rak+=sum[mid];
			ans+=mid;
		}
	}
	else{
		for(re i=1;i<=k;i++)now[i]=s2[i],sum[s2[i]]++;
		sort(now+1,now+k+1);
		int m1,r1=0,m2,r2=0;
		m1=now[k>>1];m2=now[k+2>>1];
		for(re i=1;i<=k;i++){
			if(now[i]<=m1)r1++;
			if(now[i]<=m2)r2++;
		}
		//cout<<r2<<endl;
		ans+=(m1+m2)*1.0/2.0;
		for(re i=2;i<=n-k+1;i++){
			//cout<<i<<endl;
			sum[s2[i-1]]--;
			sum[s2[i+k-1]]++;
			if(s2[i-1]<=m1)r1--;
			if(s2[i-1]<=m2)r2--;
			if(s2[i+k-1]<=m1)r1++;
			if(s2[i+k-1]<=m2)r2++;
			while(r1-sum[m1]>=(k>>1))r1-=sum[m1],m1--;
			while(r1+sum[m1+1]<(k>>1))r1+=sum[m1+1],m1++;
			if(r1<(k>>1))m1++,r1+=sum[m1];
			while(r2-sum[m2]>=(k+2>>1))r2-=sum[m2],m2--;
			while(r2+sum[m2+1]<(k+2>>1))r2+=sum[m2+1],m2++;//cout<<r2<<endl;
			if(r2<(k+2>>1))m2++,r2+=sum[m2];
			ans+=(m1+m2)*1.0/2.0;
		}
	}
	printf("%.1lf",ans);
}

·

T2 Game

呵呵呵,这个题更傻逼,傻逼到爆炸,就是一傻逼题

排序不用优先队列???,凭啥你这数的范围是1-n

凭啥???凭啥????凭啥可以用桶???

考完就5min就Ac这个题,要是我看到了数据范围,我至于只有5pts

还不只这些,这个傻逼题,它让你求差,凭啥差是负数,这是我语文不好还是你语文不好啊,不需要绝对值??

真是考个试能吧我给气死

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=1e5+5;
int n,K,a[N];
ll sco[2],sum[N];
signed main(){
	scanf("%d%d",&n,&K);
	for(re i=1;i<=n;i++)scanf("%d",&a[i]);
	while(K--){
		sco[0]=sco[1]=0;
		int p,maxn=0,now=0;scanf("%d",&p);
		for(re i=1;i<p;i++)sum[a[i]]++,maxn=max(maxn,a[i]);
		for(re i=p;i<=n;i++){
			if(a[i]>=maxn)sco[now]+=a[i];
			else{
				sum[a[i]]++;
				sum[maxn]--;
				sco[now]+=maxn;
				while(sum[maxn]==0)maxn--;
			}now^=1;
		}
		for(re i=maxn;i>=1;i--)
			while(sum[i]){
				sco[now]+=i;
				now^=1;sum[i]--;
			}
		printf("%lld\n",sco[0]-sco[1]);
	}
}

·

T3 Park

这个题还是非常有水平的,我连dfs都没有想到啊,气死了

首先有一个性质,在确定根的情况下,我在某个节点放一个面包屑,那么它对答案的贡献就是它的子节点的权值之和

所以我们dfs的时候要先预处理以1为根的时候的siz,贡献

利用两个数组,一个f[i][j]维护从i向它的子树走,一个g[i][j]由子树向他走,i表示那个节点,j表示撒了几个面包

然后就像求树上直径一样的,像点分治一样的,两两一加就好了,但是注意这个f,g是有方向的

所以我们要按照遍历儿子的顺序,正着一遍,倒着一遍

记得赋初值

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=1e5+5;
const int inf=0x3f3f3f3f;
int n,V,p[N];
int to[N*4],nxt[N*4],head[N],heed[N],rp;
ll f[N][105],g[N][105],siz[N];
//ll maxf[205],maxg[205];
ll ans;
void add_edg1(int x,int y){
	to[++rp]=y;
	nxt[rp]=head[x];
	head[x]=rp;
}
void add_edg2(int x,int y){
	to[++rp]=y;
	nxt[rp]=heed[x];
	heed[x]=rp;
}
void dfs(int x,int fa){
	for(re i=head[x];i;i=nxt[i]){
		int y=to[i];
		if(y==fa)continue;
		siz[x]+=p[y];
	}
	for(re i=head[x];i;i=nxt[i])
		if(to[i]!=fa)dfs(to[i],x);
	for(re i=1;i<=V;i++)f[x][i]=siz[x],g[x][i]=siz[x]+p[fa];
	for(re i=head[x];i;i=nxt[i]){
		int y=to[i];
		if(y==fa)continue;
		for(re j=1;j<=V;j++)ans=max(ans,g[x][j]+f[y][V-j]);
		for(re j=1;j<=V;j++)g[x][j]=max(g[x][j],max(g[y][j],g[y][j-1]+siz[x]-p[y]+p[fa]));
		for(re j=1;j<=V;j++)f[x][j]=max(f[x][j],max(f[y][j],f[y][j-1]+siz[x]));
	}
	for(re i=1;i<=V;i++)f[x][i]=siz[x],g[x][i]=siz[x]+p[fa];
	for(re i=heed[x];i;i=nxt[i]){
		int y=to[i];
		if(y==fa)continue;
		for(re j=1;j<=V;j++)ans=max(ans,g[x][j]+f[y][V-j]);
		for(re j=1;j<=V;j++)g[x][j]=max(g[x][j],max(g[y][j],g[y][j-1]+siz[x]-p[y]+p[fa]));
		for(re j=1;j<=V;j++)f[x][j]=max(f[x][j],max(f[y][j],f[y][j-1]+siz[x]));
	}
}
signed main(){
	scanf("%d%d",&n,&V);
	for(re i=1;i<=n;i++)scanf("%d",&p[i]);
	for(re i=1,x,y;i<n;i++){
		scanf("%d%d",&x,&y);
		add_edg1(x,y);add_edg1(y,x);
	}
	for(re i=1;i<=n;i++)
		for(re j=head[i];j;j=nxt[j])
			add_edg2(i,to[j]);
	//for(re i=1;i<=n;i++)f[i][0][1]=g[i][0][1]=-inf;
	dfs(1,0);
	printf("%lld",ans);
}
posted @ 2021-07-21 11:06  fengwu2005  阅读(57)  评论(0编辑  收藏  举报