前言
- 一场没有AC的考试……
- 考试的时候没有注意时间分配,导致T1T2没有什么时间。
- 又因为一些神奇的原因,暴力又都写挂了。
- 于是我死了。
T1
- 用10分钟打的multiset模拟。
- 结果忘记multiset删元素如果用元素删会把所有该元素都删掉,就Wa0了
- 改成用迭代器删除后T50。
- 后又受milkfun启发打了个对顶multiset。
- 结果还T50,只快了500ms。
- 正解其实很简单,也很暴力。
- 因为每次只会修改很少的元素而取模运算又使s2分布比较均匀,所以中位数的位置变化不大
- 直接开桶记录每个值的出现次数,通过维护小于和大于中位数指针位置数值的数量来进行指针的转移
- 感觉复杂度挺玄学的所以这题是个玄学题
#include<cstdio>
#include<set>
using namespace std;
int const N=179424680,M=1e7+5;
int s1[M],s2[M];
int p[M],tot,n,k;
bool v[N];
int qj[M],t;
int bar[N<<1];
long long ans;
inline void getp(){
for(register int i=2;i<N;++i){
if(!v[i])p[++tot]=i;
if(tot==n+1)break;
for(register int j=1;j<=tot&&i*p[j]<N;++j){
v[i*p[j]]=1;
if(!(i%p[j]))break;
}
}
return ;
}
int main(){
int ww;
scanf("%d%d%d",&n,&k,&ww);
const int mod=ww;
getp();
int lt=k>>1,lit=(k>>1)+1;
for(register int i=1;i<=n;++i)s1[i]=1ll*p[i]*i%mod;
for(register int i=1;i<=n;++i)s2[i]=s1[i]+s1[i/10+1];
for(register int i=1;i<k;++i)++bar[s2[i]];
if(k&1){
int lf=0,now=-1;
for(register int i=k;i<=n;++i){
++bar[s2[i]];
if(s2[i]<=now)++lf;
if(i!=k){
--bar[s2[i-k]];
if(s2[i-k]<=now)--lf;
}
while(lf<lit)lf+=bar[++now];
while(lf>=lit+bar[now])lf-=bar[now--];
ans+=now;
}
return printf("%lld.0",ans),0;
}
int lnow=-1,rnow=-1,lf=0,rf=0;
for(register int i=k;i<=n;++i){
++bar[s2[i]];
if(s2[i]<=lnow)++lf;
if(s2[i]<=rnow)++rf;
if(i!=k){
--bar[s2[i-k]];
if(s2[i-k]<=lnow)--lf;
if(s2[i-k]<=rnow)--rf;
}
while(lf<lt)lf+=bar[++lnow];
while(lf>=lt+bar[lnow])lf-=bar[lnow--];
while(rf<lit)rf+=bar[++rnow];
while(rf>=lit+bar[rnow])rf-=bar[rnow--];
ans+=lnow+rnow;
}
printf("%lld.",ans>>1);
putchar((ans&1)?53:48);
return 0;
}
知识兔View CodeT2
- 用10分钟打的multiset模拟。(模拟总是惊人的相似)
- 结果出题人报复社会分数差不加绝对值,就Wa5了
- 去掉绝对值后T50。
- 正解其实很简单,也很暴力。
- 对于每个p,用一个指针指向前p个最大的数。
- 可以先把第一次操作进行一半,这样每加一个元素就进行一次选择。
- 可以发现指针是不上升的,因为如果新加的一个元素更优就会直接选择,相当于没有添加元素。
- 然后就可以$\Theta(N)$扫描了,总的复杂度是$\Theta(NK)$。
#include<cstdio>
#include<algorithm>
using namespace std;
int const N=1e5+5,K=2003;
inline int read(){
int ss(0);char bb(getchar());
while(bb<48||bb>57)bb=getchar();
while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar();
return ss;
}
inline int max(int x,int y){
return x>y?x:y;
}
int n,k;
int a[N],c[N],bar[N];
pair<int,int>b[N];
long long g[2];
int main(){
n=read(),k=read();
for(register int i=1;i<=n;++i)a[i]=read(),b[i]=make_pair(a[i],i);
sort(b+1,b+n+1);
for(register int i=1,tot=0;i<=n;++i){
if(b[i].first!=b[i-1].first)c[++tot]=b[i].first;
a[b[i].second]=tot;
}
while(k--){
int x=read(),u=1,tp=0;
g[0]=g[1]=0;
for(register int i=1;i<=x;++i)++bar[a[i]],tp=max(a[i],tp);
--bar[tp],g[0]+=c[tp];
while(!bar[tp]&&tp)--tp;
for(register int i=x+1;i<=n;++i,u^=1)
if(a[i]>=tp)g[u]+=c[a[i]];
else{
++bar[a[i]],--bar[tp];
g[u]+=c[tp];
while(!bar[tp]&&tp)--tp;
}
while(tp){
g[u]+=c[tp],--bar[tp],u^=1;
while(!bar[tp]&&tp)--tp;
}
printf("%lld\n",g[0]-g[1]);
}
return 0;
}
知识兔View CodeT3
- 打了两个多小时的树形DP。
- 然后大样例死活过不去心态爆炸。
- 交上去WA44分。
- 考试后发现:
- 改成:
- WA93分。
- 一顿玄学特判AC后觉得自己程序应该不用特判,就又端详了一下代码:
- 把最后一句话删了,AC!
- 不打对拍果然遭天遣了……
- 对于节点i,考虑五种状态:
- f[i][j][0]表示以i的子节点为起点,i为终点,撒了j个面包屑,i和i的直系儿子节点不撒面包屑的最优结果。
- f[i][j][1]表示以i的子节点为起点,i为终点,撒了j个面包屑,i撒面包屑的最优结果。
- f[i][j][2]表示以i的子节点为起点,i为终点,撒了j个面包屑,i不撒面包屑,i的直系儿子撒面包屑的最优方案。
- f[i][j][3]表示以i为起点,i的子节点为终点,撒了j个面包屑,i不撒面包屑的方案数。
- f[i][j][4]表示以i为起点,i的子节点为终点,撒了j个面包屑,i撒面包屑的方案数。
- DP转移与答案统计大约有近20个转移式,max嵌套后有9个,具体看代码吧。
- 复杂度$\Theta(5Nv)$。
#include<cstdio>
#define ll long long
using namespace std;
int const N=1e5+1,M=101;
int n,v;
int head[N],to[N<<1],Next[N<<1],t;
int p[N];
ll f[N][M][5],mx[M][5],ans;
inline int read(){
int ss(0);char bb(getchar());
while(bb<48||bb>57)bb=getchar();
while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar();
return ss;
}
inline void add(int x,int y){
to[++t]=y;
Next[t]=head[x],head[x]=t;
return ;
}
inline ll max(ll x,ll y){
return x>y?x:y;
}
inline ll min(ll x,ll y){
return x<y?x:y;
}
void dfs(int x,int fa){
ll z(0);
for(register int i=head[x];i;i=Next[i])
z+=p[to[i]];
f[x][1][1]=f[x][1][4]=z;
for(int i=head[x],y;i;i=Next[i])
if((y=to[i])^fa){
dfs(y,x);
mx[1][0]=f[x][1][0],mx[1][1]=f[x][1][1],mx[1][2]=f[x][1][2];
mx[1][3]=f[x][1][3],mx[1][4]=f[x][1][4];
for(register int j=2;j<=v;++j)
mx[j][0]=max(mx[j-1][0],f[x][j][0]),
mx[j][1]=max(mx[j-1][1],f[x][j][1]),
mx[j][2]=max(mx[j-1][2],f[x][j][2]),
mx[j][3]=max(mx[j-1][3],f[x][j][3]),
mx[j][4]=max(mx[j-1][4],f[x][j][4]);
for(register int j=v,jj;j;--j){
f[x][j][0]=max(f[x][j][0],max(f[y][j][0],f[y][j][2]));
f[x][j][1]=max(f[x][j][1],max(f[y][j-1][0],max(f[y][j-1][1],f[y][j-1][2]))+z-p[y]);
f[x][j][2]=max(f[x][j][2],f[y][j][1]);
f[x][j][3]=max(f[x][j][3],max(f[y][j][3],f[y][j][4]-p[x]));
f[x][j][4]=max(f[x][j][4],max(f[y][j-1][3],f[y][j-1][4]-p[x])+z);
jj=v-j;
ans=max(ans,max(mx[jj][0],max(mx[jj][1],mx[jj][2]))+f[y][j][3]);
ans=max(ans,max(mx[jj][0],max(mx[jj][1],mx[jj][2]))+f[y][j][4]-p[x]);
ans=max(ans,mx[jj][3]+max(f[y][j][0],max(f[y][j][1],f[y][j][2])));
ans=max(ans,mx[jj][4]+max(f[y][j][0],max(f[y][j][1],f[y][j][2]))-p[y]);
}
}
for(register int i=1;i<=v;++i)
ans=max(max(ans,f[x][i][0]),max(max(f[x][i][1],f[x][i][2]),max(f[x][i][3],f[x][i][4])));
return ;
}
int main(){
n=read(),v=read();
for(register int i=1;i<=n;++i)p[i]=read();
for(register int i=1,ff,tt;i<n;++i)
ff=read(),tt=read(),add(ff,tt),add(tt,ff);
dfs(1,0);
printf("%lld",ans);
return 0;
}
知识兔View Code