$Sol$
$50pts$:我们考虑$q==0$的情况,每次在所有的蚯蚓中找到一只长度最大的,这非常二叉堆。所以我们可以用一个优先队列,随便水一下就有50分。($NOIp$的分真这么好拿?)
(理论得分60分,由于种种常数等的原因,实际会达到50分)
1 #include<cstdio> 2 #include<algorithm> 3 #include<queue> 4 5 using namespace std; 6 7 int n,m,can,u,v,t; 8 int tim[7000090]; 9 priority_queue<int>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(" "); 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 #include<cstdio> 2 #include<algorithm> 3 #include<queue> 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<ll>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(" "); 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$:正解的思维难度还是有的,先被切掉的蚯蚓长度一定比后被切掉的蚯蚓长度大。
(引用自@aiyougege,侵删)
1 #include<cstdio> 2 #include<algorithm> 3 #include<queue> 4 #include<cmath> 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<ll>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(" "); 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的部分分还是给的很足的,有时还可能不小心敲成正解?第二题还是要重视,尽量多拿分。