从前,有n只萌萌的GT,他们分成了两组在一起玩游戏。他们会排列成一排,第i只GT会随机得到一个能力值bi。在第i秒的时候,第i只GT可以消灭掉所有排在他前面的和他不是同一组的且能力值小于他的GT。 为了使游戏更加有趣,GT的首领GTW会发功m次,第i次发功的时间为ci,则在第ci秒结束后,b1,b2,...,bci都会增加1。 现在,GTW想知道在第n秒之后,会有几只GT存活下来。
第一行只有一个整数T(T≤5),表示测试数据组数。 第二行有两个整数n,m。表示GT的个数和GTW发功的次数。(1≤n≤50000,1≤m≤50000) 第三到n+2行,每行有两个整数ai,bi,表示第i只GT在哪个组和他的能力值 (0≤a[i]≤1,1≤b[i]≤106) 第n+3行到第n+m+2行,每行有一个整数ci,表示GTW第i次发功的时间。1≤c[i]≤n
总共T行,第i行表示第i组数据中,GT存活的个数。
1 4 3 0 3 1 2 0 3 1 1 1 3 4
3
第1秒后 能力值为4 2 3 1 第2秒后 能力值为4 2 3 1 第3秒后 能力值为5 3 4 1,第2只GT被第3只GT消灭掉了 第4秒后 能力值为6 4 5 2 ci并不是有序的
题意很明确,这里就不多啰嗦了。
这里详说一下我的解题经历和大牛代码的解题思想。
首先看到题意 ,小白嘛,当然是想用暴力或者模拟思路去搞定这
int a[50050]; int b[50050]; int fagong[50050]; memset(fagong,0,sizeof(fagong)); int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d%d",&a[i],&b[i]); } for(int i=0;i<m;i++) { int k; scanf("%d",&k); fagong[k]++;//题意是说可以发功多次~。所以这里每出现一次,我们就要+1. }
还是研究了好一会,并没有摆脱TLE的命运。然后默默的去找了题解,发现这个题目的解题思路是真的很巧。
这里我们用样例来举例详解。这里我们先上初始化内容代码:
这里我们知道,最后一个GT是不会死的。另外,发功是随着比较进行的,我们这里的比较步骤是这样的:先发功,然后由当前的GT向前比较的,看看前边有没有比自己小的GT.然后干掉他。如果按照模拟去做,我们这里发功的操作的时间复杂度是O(n^2)。是一定会超时的,所以我们这里形成了这样的一个巧发功的方法:逆向思维。很多时候呢,我们正向解决问题比较困难的时候,要多逆向考虑考虑,也许发现真的可行呢~。
我们这里还是按照样例来说:
初始的b是这样的:3 2 3 1
整个操作过程完成后B是这样的:6 4 5 2.
我们不难发现,当时间变到4的时候发功之后,1-4号GT的b都要+1,但是时间变到3的时候,4号GT是不会跟着变化的,由于这个特性,我们可以逆向的去+b,就达到了降低时间复杂度的任务:
for(int i=n;i>=1;i--) { fagong[i]+=fagong[i+1]; b[i]+=fagong[i]; }b处理完毕之后,我们对其中数据进行分析:6 4 5 2。
首先呢,我们要知道,是要对不同阵容的比较。所以我们这里先设上两个变量:maxn,maxn1.分别表示0号阵容的最大b,和1号阵容的最大b
如果我们这里还是正向比较。复杂度还是O(n^2)所以,这里还是用上了逆向思维。如果当前b的后边的最大不同阵容的b不足以杀死当前b,那么他就生存下来了。(这一步骤很容易理解,并且也是最重要的思路。)(大牛就是大牛。。。。。小白给跪了.....)
最终我们这里就形成了近乎完美的核心思路:这里直接上代码:
int output=0; int maxn0=-0x1f1f1f1f; int maxn1=-0x1f1f1f1f; for(int i=n;i>=1;i--) { if(a[i]==0)//如果是0阵容的GT { if(maxn1<=b[i])//如果当前这只GT的身后没有任何一只GT(当然是1阵容的)能够干掉他, output++;//那么他就生存了下来 maxn0=max(maxn0,b[i]);//实时更新身后最大值。 } if(a[i]==1) { if(maxn0<=b[i]) output++; maxn1=max(maxn1,b[i]); } } printf("%d\n",output);然后是完整的AC代码和我的超时线段树代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int a[50050]; int b[50050]; int fagong[50050]; int main() { int t; scanf("%d",&t); while(t--) { memset(fagong,0,sizeof(fagong)); int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d%d",&a[i],&b[i]); } for(int i=0;i<m;i++) { int k; scanf("%d",&k); fagong[k]++; } for(int i=n;i>=1;i--)//NB//代替了sort并且双for. { fagong[i]+=fagong[i+1]; b[i]+=fagong[i]; } int output=0; int maxn0=-0x1f1f1f1f; int maxn1=-0x1f1f1f1f; for(int i=n;i>=1;i--) { if(a[i]==0) { if(maxn1<=b[i]) output++; maxn0=max(maxn0,b[i]); } if(a[i]==1) { if(maxn0<=b[i]) output++; maxn1=max(maxn1,b[i]); } } printf("%d\n",output); } }如果某位大牛看出了我的代码哪里还能优化或者是错误了的话,请您务必指出:
#include<stdio.h> #include<string.h> #include<algorithm> #include<iostream> using namespace std; #define lson l,m,rt*2 #define rson m+1,r,rt*2+1 int shuju[121212]; int tree[121212]; int flag[121212]; int bijiao[121212]; int bijiao2[121212]; int num[121212]; int fagong[121212]; int cont; void pushup(int rt) { tree[rt]=tree[rt<<1]+tree[rt<<1|1]; } void build( int l ,int r , int rt ) { if( l == r ) { scanf("%d%d",&flag[rt],&shuju[rt]); num[rt]=cont; bijiao[cont]=shuju[rt]; bijiao2[cont]=flag[rt]; cont++; tree[rt]=1; return ; } else { int m = (l+r)>>1 ; build(lson) ; build(rson) ; pushup(rt) ; } } void update(int c,int l,int r,int rt) { if(l==r) { shuju[rt]+=c; bijiao[num[rt]]+=c; return ; } else { int m=(l+r)>>1 ; update(c,lson); update(c,rson); } } void update2(int c,int c2,int p,int l,int r,int rt) { if(l==r) { if(c>shuju[rt]&&p>num[rt]&&c2!=flag[rt]) tree[rt]=0; return ; } else { int m=(l+r)>>1 ; update2(c,c2,p,lson); update2(c,c2,p,rson); pushup(rt); } } int main() { int t; scanf("%d",&t); while(t--) { memset(fagong,0,sizeof(fagong)); cont=0; int n,m; scanf("%d%d",&n,&m); build(1,n,1); //printf("yes\n"); int fagong[10000]; for(int i=0;i<m;i++) { int k; scanf("%d",&k); k--; fagong[k]++; } sort(fagong,fagong+m); for(int i=0;i<n;i++) { //printf("%d\n",bijiao[i]); if(fagong[i])update(fagong[i],1,n,1); update2(bijiao[i],bijiao2[i],i,1,n,1); } printf("%d\n",tree[1]); } }