A:http://codeforces.com/contest/1420/problem/A
题意:
最多交换n*(n-1)/2-1次,是否能把序列变成非递减序列
解析:
冒泡排序最差的情况是n*(n-1)/2,最差情况就是全递减。所以判断序列是否为单调递减即可。
#include <bits/stdc++.h> #include<vector> using namespace std; typedef long long ll; const int maxn = 1e6+10; int a[maxn]; int pr[maxn]; bool st[maxn]; //vector<int>g[maxn]; int cnt=0; void _get(ll n) { memset(st,false,sizeof(st)); for(int i=2;i<=n;i++) { if(!st[i]) { pr[cnt++]=i; } for(int j=i+i;j<=n;j+=i) { st[j]=true; } } } int main(){ int t; cin>>t; while(t--) { int n; cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; int ok=0; for(int i=2;i<=n;i++) { if(a[i-1]<=a[i]) { ok=1;break; } } if(ok) cout<<"YES"<<endl; else cout<<"NO"<<endl; } }
B:http://codeforces.com/contest/1420/problem/B
题意:
存在几对(i,j),i<j满足:
ai & aj≥ai⊕aj
解析:
&运算:都为1,则为1,否则为0
xor运算:不同则为1,相同则为0
由此得出,对于ai和aj,只需要判断它们的二进制第一位是否相同即可。相同即能组成一对。
我这边是统计的的ai最大能到几次幂,map记录。
对于n个数,可以组成((n-1)^2+(n-1))/2对
#include <bits/stdc++.h> #include<vector> #include<map> using namespace std; typedef long long ll; const int maxn = 1e6+10; ll a[maxn]; int pr[maxn]; bool st[maxn]; //vector<int>g[maxn]; int cnt=0; void _get(ll n) { memset(st,false,sizeof(st)); for(int i=2;i<=n;i++) { if(!st[i]) { pr[cnt++]=i; } for(int j=i+i;j<=n;j+=i) { st[j]=true; } } } int main(){ int t; cin>>t; while(t--) { ll n; cin>>n; map<ll,ll>mm; for(int i=1;i<=n;i++) { cin>>a[i]; int cnt=0; for(int j=0;j<33;j++) { ll md=pow(2,j); if(md>a[i]) { mm[cnt]++; break; } else { cnt=j; } } // cout<<cnt<<endl; } ll all=0; for(int i=0;i<32;i++) { if(mm[i]==0) continue; ll md=mm[i]; md=((md-1)*(md-1)+(md-1))/2; all+=md; } cout<<all<<endl; } }
C1:http://codeforces.com/contest/1420/problem/C1
题意:
n,q
n个数,q次交换(C1的q=0,无交换操作)
找出最大的Ab1-Ab2+Ab3.....
1<=b1<b2<b3....<=n
解析:
解法1:贪心找峰点和谷点
经过分析,对于一段上升的序列,我们需要加上最高的那个点,对于一段递减的序列,我们需要减去最低的那个点
所以就是峰点和谷点了,找这些点对即可。
两种找寻方式:
(1)比较麻烦,但是很巧妙,很锻炼人。L负责记录每一段上升序列的最大值,R记录每一段递减序列的最小值。
#include <bits/stdc++.h> #include<vector> #include<map> using namespace std; typedef long long ll; const int maxn=3e5+10; int a[maxn]; int pr[maxn]; bool st[maxn]; int main(){ int t; cin>>t; while(t--) { int n,q; cin>>n>>q; for(int i=1;i<=n;i++) cin>>a[i]; int l = 0 , r = 0; ll sum=0; for(int i=1;i<=n;i++) { if(i==1) { l=a[i]; } else { if(a[i]>a[i-1]) { if(l&&r) sum+=l-r; l=a[i]; r=0; } else { r=a[i]; } } } sum+=l;//注意 cout<<sum<<endl; } }
(2)直接判断峰谷点。
#include <bits/stdc++.h> #include<vector> #include<map> using namespace std; typedef long long ll; const int maxn=3e5+10; int a[maxn]; int pr[maxn]; ll dp1[maxn],dp2[maxn]; bool st[maxn]; int main(){ int t; cin>>t; while(t--) { int n,q; cin>>n>>q; for(int i=1;i<=n;i++) cin>>a[i]; ll sum=0; a[0]=0,a[n+1]=0; for(int i=1;i<=n;i++) { if(a[i]>a[i-1]&&a[i]>a[i+1]) sum+=a[i]; if(a[i]<min(a[i-1],a[i+1])) sum-=a[i]; } cout<<sum<<endl; } }
解法2:DP
规定dp1[i]表示,在i位置,所选序列长度为奇数,那么对于当前ai,选或者不选。不选的话dp1[i-1],选的话,利用上次的偶数长度dp2[i-1]+a[i]
dp2[i]同理,在i位置,所选序列长度为偶数。
#include <bits/stdc++.h> #include<vector> #include<map> using namespace std; typedef long long ll; const int maxn=3e5+10; int a[maxn]; int pr[maxn]; ll dp1[maxn],dp2[maxn]; bool st[maxn]; int main(){ int t; cin>>t; while(t--) { int n,q; cin>>n>>q; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++) { dp1[i]=max(dp1[i-1],dp2[i-1]+a[i]); dp2[i]=max(dp2[i-1],dp1[i-1]-a[i]); } cout<<max(dp1[n],dp2[n])<<endl; } }
C2:http://codeforces.com/contest/1420/problem/C2
承接上述的解法1,直接判断谷点的解法。
对于一个位置i,如果它被交换掉,那么就会对相邻的i-1,i+1产生影响。即,三个点都受到了影响。那么交换一次,就需要对之前的统计操作进行取消,即:
void del(int i) { if(!f[i]||i==0||i==n+1) return ; f[i]=0; if(a[i]>max(a[i-1],a[i+1])) sum-=a[i]; else if(a[i]<min(a[i-1],a[i+1])) sum+=a[i]; return ; }
del(l-1);del(l);del(l+1); del(r-1);del(r);del(r+1);
引入f[],防止重复取消或统计。
取消以后,进行对应的交换。
进行重新统计,统计也是仅限于这三个点,因为这几个点是否是峰谷点的属性本身有可能发生改变,对总体答案只是局部的影响。
具体的见代码吧:
#include <bits/stdc++.h> #include<vector> #include<map> using namespace std; typedef long long ll; const int maxn=3e5+10; int a[maxn],n,f[maxn]; //int pr[maxn]; //ll dp1[maxn],dp2[maxn]; //bool st[maxn]; ll sum=0; void insert(int i) { if(f[i]||i==0||i==n+1) return ; f[i]=1; if(a[i]>max(a[i-1],a[i+1])) sum+=a[i]; else if(a[i]<min(a[i-1],a[i+1])) sum-=a[i]; return ; } void del(int i) { if(!f[i]||i==0||i==n+1) return ; f[i]=0; if(a[i]>max(a[i-1],a[i+1])) sum-=a[i]; else if(a[i]<min(a[i-1],a[i+1])) sum+=a[i]; return ; } int main(){ int t; cin>>t; while(t--) { int q; cin>>n>>q; for(int i=1;i<=n;i++) cin>>a[i],f[i]=0; a[0]=0;a[n+1]=0; sum=0; for(int i=1;i<=n;i++) insert(i); cout<<sum<<endl; while(q--) { int l,r; cin>>l>>r; del(l-1);del(l);del(l+1); del(r-1);del(r);del(r+1); swap(a[l],a[r]); insert(l-1);insert(l);insert(l+1); insert(r-1);insert(r);insert(r+1); cout<<sum<<endl; } } }