【学长出题】【比赛题解】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 }
posted @ 2017-09-29 18:11  粉兔  阅读(262)  评论(0编辑  收藏  举报