這次比賽由dalao學長@FallDream出題,歡迎查看他的blog!ios
【T1】數組
題意:spa
樣例:3d
(1<=n<=100000, 1<=xi,yi<=10^9)code
題解:blog
加一個骨牌,就至關於把最後的若干個骨牌刪除,再算以前的答案。排序
若是咱們對任意的前i個骨牌算出答案,就能夠簡單地算出最終答案。get
就有了dp的想法,能夠發現是比較簡單的。it
f[i]=f[k]+(i-k),k是i推倒後最後一個沒有被推倒的骨牌編號。io
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 }