附:官方题解传送门
离散化+树状数组,O(2n*log(2n))的复杂度,实测运行841ms。
#include
using namespace std;
const int N=2e5+10;
int n,a[N],b[N],d[2*N],t[2*N],num1[2*N],num2[N];
struct node
{
int tr[2*N];
int lowbit(int x)
{return x&(-x);}
void add(int pos,int k)
{
for(int i=pos;i<=2*n;i+=lowbit(i))
tr[i]+=k;
}
int sum(int pos)
{
int s=0;
for(int i=pos;i;i-=lowbit(i))
s+=tr[i];
return s;
}
}T1,T2;//两个树状数组
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
{
cin>>b[i];
d[i]=a[i]-b[i];
d[i+n]=-d[i];//相反数
t[i]=d[i];//t是d的备份
t[i+n]=d[i+n];
}
stable_sort(t+1,t+2*n+1);
for(int i=1;i<=2*n;i++)
{
int k=lower_bound(t+1,t+2*n+1,d[i])-t;
num1[i]=k;//num是d离散化后的数组(总共)
T1.add(num1[i],1);
if(i>n)
{
num2[i-n]=k;
T2.add(num2[i-n],1);
}
}
long long ans=0;
for(int i=1;i<=n;i++)
{
T1.add(num1[i],-1);
T1.add(num2[i],-1);
T2.add(num2[i],-1);
int s1=T1.sum(2*n)-T1.sum(num2[i]);//总共比num2[i]大的数的个数
int s2=T2.sum(2*n)-T2.sum(num2[i]);//在相反数的数组中比num2[i]大的数的个数
ans+=s1-s2;
}
printf("%lld\n",ans);
return 0;
}
后来看了大佬们的代码,发现这题我又想复杂了,没必要上树状数组维护。
找到公式,类似尺取计数即可。O(n*logn)的复杂度,实测运行156ms。
#include
#define ll long long
using namespace std;
ll const maxn=2e5+5;
ll n,a[maxn],b[maxn],c[maxn],l,r,ans;
int main()
{
scanf("%lld",&n);
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]);
for(int i=1;i<=n;++i)
scanf("%lld",&b[i]);
for(int i=1;i<=n;++i)
c[i]=a[i]-b[i];
sort(c+1,c+1+n);
l=1,r=n,ans=0;
while(1)
{
if(c[l]+c[r]>0){ans+=r-l;r--;}
else l++;
if(r==l) break;
}
cout<<ans<<endl;
return 0;
}
0是起点,n+1是终点,每次根据当前位置是L还是R可以选择向后或向前跳[1,d]步(不能超过范围),特别地,对于0位置和n+1位置,我们可以当作是R。
贪心,显然跳到L就只能往后退直到为R,那么不如直接刚开始就跳到刚才回退到的R,不用多走这些冤枉路,所以策略就是每次只跳R,因此我们只需要找相邻的R距离最大值,这样就能保证每次都能跳到R,一直踩着R前进,这是最短的路径。
#include
using namespace std;
const int N=2e5+10;
int T;
char s[N];
int main()
{
ios::sync_with_stdio(false);
cin>>T;
while(T--)
{
cin>>s+1;
int pos=0;
int n=strlen(s+1);
s[n+1]='R';
int mx=0;
for(int i=1;i<=n+1;i++)
if(s[i]=='R'){mx=max(mx,i-pos);pos=i;}
printf("%d\n",mx);
}
return 0;
}
这个很简单,找长度为3的回文就行,但是没注意特判三个数均相等的情况,被hack了
#include
using namespace std;
const int N=5050;
int T,n,a[N],vis[N];
bool judge()
{
for(int i=1;i<=n;i++)
{
if(vis[a[i]]&&i-vis[a[i]]>=2)return 1;
vis[a[i]]=i;
}
return 0;
}
int main()
{
ios::sync_with_stdio(false);
cin>>T;
while(T--)
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
memset(vis,0,sizeof(vis));
if(judge())printf("YES\n");
else printf("NO\n");
}
return 0;
}
hack:
1 3
1 1 1
正确输出:YES
修改后的AC代码:
#include
using namespace std;
const int N=5050;
int T,n,a[N],vis[N];
bool judge()
{
for(int i=1;i<=n;i++)
{
if(vis[a[i]]&&i-vis[a[i]]>=2||(i-1>=1&&i+1<=n&&a[i]==a[i-1]&&a[i]==a[i+1]))return 1;
//注意特判三个连续的数相等的情况
vis[a[i]]=i;
}
return 0;
}
int main()
{
ios::sync_with_stdio(false);
cin>>T;
while(T--)
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
memset(vis,0,sizeof(vis));
if(judge())printf("YES\n");
else printf("NO\n");
}
return 0;
}
类似俄罗斯方块,但是如果只有一列,那么它自己也会消失到高度为0。
不难发现,只要高度全部为奇数或者全部为偶数即可全部消去。
#include
using namespace std;
int a[110],n,T;
bool judge()
{
int f1=0,f2=0;
for(int i=1;i<=n;i++)
{
if(a[i]&1)f1++;//奇数
else f2++;//偶数
if(f1&&f2)return 0;
}
return 1;
}
int main()
{
ios::sync_with_stdio(false);
cin>>T;
while(T--)
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
if(judge())printf("YES\n");
else printf("NO\n");
}
return 0;
}