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);
}
QQ:2953174821