$Sol$
$50pts$:我们考虑$q==0$的情况,每次在所有的蚯蚓中找到一只长度最大的,这非常二叉堆。所以我们可以用一个优先队列,随便水一下就有50分。($NOIp$的分真这么好拿?)
(理论得分60分,由于种种常数等的原因,实际会达到50分)
1 #include2 #include 3 #include 4 5 using namespace std; 6 7 int n,m,can,u,v,t; 8 int tim[7000090]; 9 priority_queue q;10 11 int main()12 {13 scanf("%d%d%d%d%d%d",&n,&m,&can,&u,&v,&t);14 if(can==0)15 {16 for(int i=1;i<=n;i++)17 {18 int x=0;19 scanf("%d",&x);q.push(x);20 }21 for(int i=1;i<=m;i++)22 {23 int tmp=q.top();q.pop();tim[i]=tmp;24 int a=u*tmp/v;int b=tmp-a;25 q.push(a);q.push(b);26 }27 for(int i=t;i<=m;i+=t)28 printf("%d ",tim[i]);29 printf("\n");30 for(int i=1;i<=n+m;i++)31 {32 if(q.empty()) break;33 if(i%t==0) printf("%d ",q.top());34 q.pop();35 }36 }37 return 0;38 }
$85pts$:我们不得不考虑每次切蚯蚓后其他的蚯蚓长度情况(为了拿到更多的部分分),我们不妨考虑下线段树和分块中的思想。
Chemist:线段树中最精妙的设计是什么?
我:懒标记!
Chemist:对!你就往这想。
我们并不需要每次都把其他蚯蚓的长度增加,而是等需要他们的时候再增加。于是,我们同样在维护一个二叉堆(优先队列),但是这里面存的是还是最初的蚯蚓们长度。我们再维护一个增量即可。
另外这道题是著名的卡常数代表,开始我80分是因为开了$longlong$,有位老哥和我打暴力的方法一样,然后它用$int+double$转化卡到了85分。
1 #include2 #include 3 #include 4 5 using namespace std; 6 typedef long long ll; 7 8 ll n,m,can,u,v,t; 9 ll sigma;10 priority_queue q;11 12 void re(ll &x)13 {14 x=0;15 char ch=getchar();16 bool flag=false;17 while(ch<'0'||ch>'9') flag|=(ch=='-'),ch=getchar();18 while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();19 x=flag ? -x : x;20 }21 22 int main()23 {24 re(n),re(m),re(can),re(u),re(v),re(t);25 for(register int i=1;i<=n;i++)26 {27 ll x=0;28 re(x);q.push(x);29 }30 for(register int i=1;i<=m;i++)31 {32 ll tmp=q.top()+sigma;q.pop();//输出要把增量带上 33 if(i%t==0) printf("%lld ",tmp);34 ll a=1ll*u*tmp/v;ll b=tmp-a;35 a-=sigma;b-=sigma;//进优先队列的都是不带增量的 36 a-=can;b-=can;//为了防止以后被认为在这时刻增加了 现在先减去 37 q.push(a);q.push(b);38 sigma+=can;//继续维护增量 39 }40 printf("\n");41 for(register int i=1;i<=n+m;i++)42 {43 if(q.empty()) break;44 if(i%t==0) printf("%lld ",q.top()+sigma);45 q.pop();46 }47 return 0;48 }
$100pts$:正解的思维难度还是有的,先被切掉的蚯蚓长度一定比后被切掉的蚯蚓长度大。
(引用自@,侵删)
1 #include2 #include 3 #include 4 #include 5 6 using namespace std; 7 typedef long long ll; 8 9 ll n,m,q,t,sigma;10 double u,v,p;11 ll qiuyin[100090];12 queue q1,q2,qq;13 14 bool cmp(ll a,ll b)15 {16 return a>b;17 }18 19 int main()20 {21 scanf("%lld%lld%lld%lf%lf%lld",&n,&m,&q,&u,&v,&t);22 p=u/v;23 for(int i=1;i<=n;i++) scanf("%lld",&qiuyin[i]);24 sort(qiuyin+1,qiuyin+1+n,cmp);25 for(int i=1;i<=n;i++) qq.push(qiuyin[i]);26 for(int i=1;i<=m;i++)27 {28 ll len=0,len1=0,len2=0;29 ll qwq=-1e16-7,qaq=-1e16-7,orz=-1e16-7;30 if(!q1.empty()) qwq=q1.front();31 if(!q2.empty()) qaq=q2.front();32 if(!qq.empty()) orz=qq.front();33 if(!q1.empty()&&qwq>=qaq&&qwq>=orz) q1.pop();34 else if(!q2.empty()&&qaq>=qwq&&qaq>=orz) q2.pop();35 else if(!qq.empty()&&orz>=qaq&&orz>=qwq) qq.pop();36 37 len=max(max(qwq,qaq),orz);len+=sigma;38 if(i%t==0) printf("%lld ",len);39 len1=floor(p*len)-q-sigma;40 len2=len-floor(p*len)-q-sigma;41 q1.push(len1),q2.push(len2);42 sigma+=q;43 }44 printf("\n");45 for(int i=1;i<=n+m;i++)46 {47 ll len=0,qwq=-1e16-7,qaq=-1e16-7,orz=-1e16-7;48 if(!q1.empty()) qwq=q1.front();49 if(!q2.empty()) qaq=q2.front();50 if(!qq.empty()) orz=qq.front();51 if(!q1.empty()&&qwq>=qaq&&qwq>=orz) q1.pop();52 else if(!q2.empty()&&qaq>=qwq&&qaq>=orz) q2.pop();53 else if(!qq.empty()&&orz>=qaq&&orz>=qwq) qq.pop();54 len=max(max(qwq,qaq),orz)+sigma;55 if(i%t==0) printf("%lld ",len);56 }57 return 0;58 }
但是期间奥妙重重WA了无数次,也不知怎么肥事。重敲就活过来了,可能是精度问题的锅,还需要注意下。
小结:NOIp的部分分还是给的很足的,有时还可能不小心敲成正解?第二题还是要重视,尽量多拿分。