学长出题比赛题解17-09-29
Posted PinkRabbit
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学长出题比赛题解17-09-29相关的知识,希望对你有一定的参考价值。
此次比赛由dalao学长@FallDream出题,欢迎查看他的blog!
【T1】
题意:
样例:
(1<=n<=100000, 1<=xi,yi<=10^9)
题解:
加一个骨牌,就相当于把最后的若干个骨牌删除,再算之前的答案。
如果我们对任意的前i个骨牌算出答案,就可以简单地算出最终答案。
就有了dp的想法,可以发现是比较简单的。
f[i]=f[k]+(i-k),k是i推倒后最后一个没有被推倒的骨牌编号。
1 #include<cstdio> 2 #include<algorithm> 3 typedef std::pair<int,int> P; 4 P a[100001]; 5 int n,f[100001],Ans=100000; 6 int main(){ 7 freopen("card.in","r",stdin); 8 freopen("card.out","w",stdout); 9 scanf("%d",&n); 10 for(int i=1;i<=n;++i) scanf("%d%d",&a[i].first,&a[i].second); 11 std::sort(a+1,a+n+1); 12 // for(int i=1;i<=n;++i) printf("%d %d\\n",a[i].first,a[i].second); 13 for(int i=1;i<=n;++i){ 14 int R=std::lower_bound(a+1,a+n+1,P(a[i].first-a[i].second,0)) - a; 15 f[i] = f[R-1] + i-R; 16 // printf("%d ",f[i]); 17 if(Ans > f[i] + n-i) Ans = f[i] + n-i; 18 } 19 printf("%d",Ans); 20 return 0; 21 }
【T2】
题意:
样例:
题解:
易证,一个数组的海棠度,一定有\\(j=i+1\\)。
那么,如果记\\(dif_{i}=\\left|a_{i+1}-a_{i}\\right|\\left(1\\leqslant i<n\\right)\\),就能把题目转化成求某个区间中所有子串的最大值之和。
考虑枚举最大值的位置,计算能使它成为最大值的区间个数。
我们需要求出某个数往左第一个大于它的数的位置,往右第一个不小于它的数的位置。
而这是能够使用单调栈维护的。
统计答案时用乘法原理,注意开ll。
1 #include<cstdio> 2 const int INF=2147483647; 3 int n,q,a[100001],left[100001],right[100001],l,r; 4 int stk[100001],top=0; 5 inline int Abs(int e){return e>0?e:-e;} 6 inline int Min(int p,int q){return p<q?p:q;} 7 inline int Max(int p,int q){return p>q?p:q;} 8 int main(){ 9 freopen("array.in","r",stdin); 10 freopen("array.out","w",stdout); 11 scanf("%d%d",&n,&q); 12 for(int i=1;i<=n;++i) scanf("%d",a+i); 13 for(int i=1;i<n;++i) a[i]=Abs(a[i+1]-a[i]); 14 n--; 15 a[0]=a[n+1]=INF; 16 top=0; stk[++top]=0; 17 for(int i=1;i<=n;++i){ 18 while(top&&a[stk[top]]<=a[i]) --top; 19 left[i]=stk[top]+1; 20 stk[++top]=i; 21 } 22 top=0; stk[++top]=n+1; 23 for(int i=n;i>=1;--i){ 24 while(top&&a[stk[top]]<a[i]) --top; 25 right[i]=stk[top]-1; 26 stk[++top]=i; 27 } 28 // for(int i=1;i<=n;++i) printf("%d ",a[i]); puts(""); 29 // for(int i=1;i<=n;++i) printf("%d ",left[i]); puts(""); 30 // for(int i=1;i<=n;++i) printf("%d ",right[i]); puts(""); 31 while(q--){ 32 long long sum=0; 33 int ll,rr; 34 scanf("%d%d",&l,&r); 35 for(int i=l;i<r;++i){ 36 ll=Max(l,left[i]); 37 rr=Min(r-1,right[i]); 38 sum+=1ll*a[i]*(i-ll+1)*(rr-i+1); 39 } 40 printf("%lld\\n",sum); 41 } 42 return 0; 43 }
【T3】
题意:
样例:
题解:
考虑把所有怪物分成两类,\\(a_{i}<b_{i}\\)的和\\(a_{i}\\geqslant b_{i}\\)的。
那么,我们先打①类怪物,一定没毛病……
把①类怪物按照\\(a_{i}\\)从小到大排序,一个个尝试能否打败。
对于②类怪物我们反过来考虑,先计算出打完所有怪物后的生命值\\({h}\'\\),然后将②类怪物的\\(a_{i}\\)与\\(b_{i}\\)交换,相同处理。
1 #include<algorithm> 2 #include<iostream> 3 #include<cstdio> 4 #define pa pair<int,int> 5 #define MN 200000 6 using namespace std; 7 inline int read() 8 { 9 int x=0;char ch=getchar(); 10 while(ch<\'0\'||ch>\'9\')ch=getchar(); 11 while(ch>=\'0\'&&ch<=\'9\')x=x*10+ch-\'0\',ch=getchar(); 12 return x; 13 } 14 int n,top1=0,top2=0,a[MN+5],b[MN+5],rk1[MN+5],rk2[MN+5],id1[MN+5],id2[MN+5];long long m,M; 15 pa q1[MN+5],q2[MN+5]; 16 bool cmp1(int x,int y){return q1[x]<q1[y];} 17 bool cmp2(int x,int y){return q2[x]<q2[y];} 18 int main() 19 { 20 freopen("atm.in","r",stdin); 21 freopen("atm.out","w",stdout); 22 n=read();M=m=read(); 23 for(int i=1;i<=n;++i) 24 { 25 int x=read(),y=read();M+=y-x; 26 if(x<=y) q1[++top1]=make_pair(x,y),id1[top1]=i; 27 else q2[++top2]=make_pair(y,x),id2[top2]=i; 28 rk1[i]=rk2[i]=i; 29 } 30 if(M<0) return 0*puts("-1"); 31 sort(rk1+1,rk1+top1+1,cmp1);sort(rk2+1,rk2+top2+1,cmp2); 32 for(int i=1;i<=top1;++i) 33 { 34 int x=rk1[i]; 35 if((m-=q1[x].first)<=0) return 0*puts("-1"); 36 m+=q1[x].second; 37 } 38 for(int i=1;i<=top2;++i) 39 { 40 int x=rk2[i]; 41 if((M-=q2[x].first)<=0) return 0*puts("-1"); 42 M+=q2[x].second; 43 } 44 for(int i=1;i<=top1;++i) printf("%d ",id1[rk1[i]]); 45 for(int i=top2;i;--i) printf("%d ",id2[rk2[i]]); 46 return 0; 47 }
以上是关于学长出题比赛题解17-09-29的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #372 +#373 部分题解
四校联考比赛题解FJ NOIP 四校联考 2017 Round 7