T1:排序后离散化。pos[i]记录第i块骨牌倒塌后会影响到的最远骨牌数,可以通过二分查找求得。
枚举放置骨牌能够使某一位置及其之后的骨牌全部倒塌时被毁坏的骨牌个数,对所有值取min即可。
Code:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define inf 0x7fffffff 5 #define MN 100005 6 using namespace std; 7 inline int in(){ 8 int x=0;bool f=0; char c; 9 for (;(c=getchar())<'0'||c>'9';f=c=='-'); 10 for (x=c-'0';(c=getchar())>='0'&&c<='9';x=(x<<3)+(x<<1)+c-'0'); 11 return f?-x:x; 12 } 13 struct st{ 14 int p,t; 15 }a[MN]; 16 int pos[MN],sum[MN],p2[MN],n,res=inf; 17 inline bool cmp(st a,st b){return a.p<b.p;} 18 int main() 19 { 20 n=in();a[0].p=-inf;pos[0]=sum[0]=0; 21 for (int i=1;i<=n;++i){a[i].p=in();a[i].t=a[i].p-in();} 22 sort(a+1,a+n+1,cmp); 23 for (int i=0;i<=n;++i) p2[i]=a[i].p; 24 for (int i=1;i<=n;++i) pos[i]=lower_bound(p2,p2+n+1,a[i].t)-p2; 25 for (int i=0;i<=n;++i){ 26 if (pos[i]>0) sum[i]=sum[pos[i]-1]+(i-pos[i]); 27 res=min(res,sum[i]+(n-i)); 28 }printf("%d",res);return 0; 29 }
T2:可被看作为点与点的斜率的绝对值。
可以发现,当选取三个点A(x1,y1),B(x2,y2),C(x3,y3)(x1<x2<x3)时,kAC一定小于或等于kAB或kBC.(kXY即为直线XY的斜率)
以此类推,选取多个点时的最大值只可能在相邻位置取到。
考虑将原数组差分后求绝对值,则一个数组的所有子数组的值之和即变为一个数组的所有子数组的最大值之和。
单调栈维护差分求绝对值后的值。注意不能取到l前的数。
Code:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define ll long long 5 #define MN 100005 6 #define zxyer array 7 using namespace std; 8 inline int in(){ 9 int x=0;bool f=0; char c; 10 for (;(c=getchar())<'0'||c>'9';f=c=='-'); 11 for (x=c-'0';(c=getchar())>='0'&&c<='9';x=(x<<3)+(x<<1)+c-'0'); 12 return f?-x:x; 13 } 14 int d[MN],st[MN],a[MN]; 15 int n,q,l,r,top; 16 ll sum[MN],ans; 17 int main() 18 { 19 n=in();q=in(); 20 for (int i=1;i<=n;++i) a[i]=in(),d[i]=abs(a[i]-a[i-1]); 21 for (int i=1;i<=q;++i){ 22 l=in();r=in();top=0; 23 st[top]=l;ans=0ll; 24 for (int j=l+1;j<=r;++j){ 25 while (top&&d[st[top]]<d[j]) --top;st[++top]=j; 26 sum[top]=sum[top-1]+1ll*(j-st[top-1])*d[j];ans+=sum[top]; 27 }printf("%lld ",ans); 28 }return 0; 29 }
T3:将所有数据按照生命值净收益与净损失分类排序。
对于净收益类,按a[i]从小到大排序,若当前生命值小于或等于a[i],则输出-1,否则生命值加上b[i]-a[i]记录答案。
对于净损失类,可以发现可以求出过程结束后的总生命值。
考虑逆向按b[i]从小到大排序,若当前生命值小于或等于b[i],则输出-1,否则生命值加上a[i]-b[i]并记录答案。
注意输出时净收益类正序输出,净损失类倒序输出。
Code:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define MN 200005 5 using namespace std; 6 inline int in(){ 7 int x=0;bool f=0; char c; 8 for (;(c=getchar())<'0'||c>'9';f=c=='-'); 9 for (x=c-'0';(c=getchar())>='0'&&c<='9';x=(x<<3)+(x<<1)+c-'0'); 10 return f?-x:x; 11 } 12 struct mon{ 13 int a,b,id; 14 }p1[MN],p2[MN]; 15 int st1[MN],st2[MN]; 16 int n,h,k,cnt1=0,cnt2=0,top1=0,top2=0,s,t; 17 inline bool cmp1(mon x,mon y){return x.a==y.a?x.b>y.b:x.a<y.a;} 18 inline bool cmp2(mon x,mon y){return x.b==y.b?x.a>y.a:x.b<y.b;} 19 int main() 20 { 21 n=in();k=h=in();for (int i=1;i<=n;++i){ 22 s=in();t=in();k+=t-s; 23 if (s<=t) p1[++cnt1].a=s,p1[cnt1].b=t,p1[cnt1].id=i; 24 else p2[++cnt2].a=s,p2[cnt2].b=t,p2[cnt2].id=i; 25 }if (k<=0) {printf("-1");return 0;} 26 sort(p1+1,p1+cnt1+1,cmp1);sort(p2+1,p2+cnt2+1,cmp2); 27 for (int i=1;i<=cnt1;++i){ 28 if (h<=p1[i].a) {printf("-1");return 0;} 29 h+=(p1[i].b-p1[i].a);st1[++top1]=p1[i].id; 30 }for (int i=1;i<=cnt2;++i){ 31 if (k<=p2[i].b) {printf("-1");return 0;} 32 k+=(p2[i].a-p2[i].b);st2[++top2]=p2[i].id; 33 }for (int i=1;i<=top1;++i) printf("%d ",st1[i]); 34 for (int i=top2;i;--i) printf("%d ",st2[i]);return 0; 35 }