“浪潮杯”第九届山东省ACM大学生程序设计竞赛(重现赛)E.sequence(树状数组求逆序对(划掉))
E.sequence
•题意
定义序列 p 中的 "good",只要 i 之前存在 pj < pi,那么,pi就是 "good";
求删除一个数,使得序列中 "good" 的个数最多;
•题解
一个数 pi 对 "good" 的贡献有两个来源:
①pi 本身为"good",对答案的贡献为 1;
②删除 pi 后,i 之后的本来是 "good" 的数因为 pi 被删除而变成非 "good" 数,这样的数有多少个,pi对答案的贡献就是多少;
贡献①好求,主要是贡献②的求解方法;
定义 fir,sec 为第一小,第二小的数;
枚举位置 i,判断 pi 与 fir,sec 的大小关系;
①如果 pi > min{fir,sec},那么 pi 本身就为 "good";
(1)如果 pi > sec,删除其之前的任何一个数,都不会使 pi 由 "good" 变为 非 "good";
(2)如果 fir > pi > sec,那么,删除 fir 会使得 pi 由 "good" 变为 非"good";
②pi < min{fir,sec},pi 本身对答案无贡献;
•AC代码
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define INF 0x3f3f3f3f 5 #define lowbit(x) (x&-x) 6 #define mem(a,b) memset(a,b,sizeof(a)) 7 const int maxn=1e6+50; 8 9 int n; 10 int p[maxn]; 11 int a[maxn];///a[i]:判断p[i]对答案的影响 12 13 int Solve() 14 { 15 int fir=INF; 16 int sir=INF; 17 for(int i=1;i <= n;i++) 18 { 19 if(p[i] > fir) 20 { 21 a[p[i]]++; 22 if(p[i] < sir) 23 a[fir]++; 24 } 25 26 if(p[i] < fir) 27 { 28 sir=fir; 29 fir=p[i]; 30 } 31 else if(p[i] < sir) 32 sir=p[i]; 33 } 34 35 int ans; 36 int ansTot=n+1; 37 for(int i=1;i <= n;++i) 38 { 39 int cur=a[p[i]]; 40 if(ansTot > cur) 41 { 42 ans=p[i]; 43 ansTot=cur; 44 } 45 else if(ansTot == cur && ans > p[i]) 46 ans=p[i]; 47 } 48 return ans; 49 } 50 int main() 51 { 52 // freopen("C:\\Users\\hyacinthLJP\\Desktop\\in&&out\\contest","r",stdin); 53 int test; 54 scanf("%d",&test); 55 while(test--) 56 { 57 scanf("%d",&n); 58 for(int i=1;i <= n;i++) 59 { 60 scanf("%d",p+i); 61 a[i]=0; 62 } 63 printf("%d\n",Solve()); 64 } 65 return 0; 66 }
•踩坑
刚开始判断其本身的影响和对其他的数的影响时,用的是树状数组求逆序对判断的(TLE到死);
其实完全没必要记录这么多信息,只需记录某数前的第一小和第二小的数即可;
•神评测鸡
用之前AC的代码,Ctrl+C , Ctrl+V,TLE???
AC之前用的是 ++i,一直TLE,改成 i++,AC???