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 ;
}
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;
}
}
}