CF903D Almost Difference
不过多赘述题意与解题方法,其他题解都已经讲的很好了。
这里提供一种不依赖 map
的 \(O(n)\) 做法。
如果值域很小,那么显然我们可以倒着跑,记录当前每个数出现了几次,然后进行计算。
于是我们可以进行一个离散化,把值域缩小。
但是如果直接离散化,会导致原本两个数相差不为1但是离散完以后相差等于1。
为避免这种情况,我们把离散化修改一下。代码如下:
#define ll __int128
#define f(i,a,b) for(ll i=a;i<=b;i++)
ll a[200010],cnt;//原数组,计数器
struct node{ll x,id;}b[200010];
bool cmp(node a,node b){return a.x<b.x;}
//主函数内
f(i,1,n)b[i]={a[i],i};
sort(b+1,b+n+1,cmp);
f(i,1,n){
if(b[i].x!=b[i-1].x){
if(b[i].x-b[i-1].x==1)cnt++;
else cnt+=2;
}a[b[i].id]=cnt;
}
若排完序后相邻两个数相等,那么这个数就等于当前的 \(cnt\)。
要不然如果差等于1,就将 \(cnt\) 加一。
否则 \(cnt\) 加2。
这样就不仅保证了值域降下来,而且使得差不为1的元素不会互相影响。
完整代码(使用__int128
):
// Problem: D. Almost Difference
// Contest: Codeforces - Educational Codeforces Round 34 (Rated for Div. 2)
// URL: https://codeforces.com/contest/903/problem/D
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// Author: jimmyywang
#include<bits/stdc++.h>
using namespace std;
#define ll __int128
#define f(i,a,b) for(ll i=a;i<=b;i++)
#define wt int tt=d;while(tt--)
#define py puts("Yes")
#define pn puts("No")
#define fe(i,e) for(int i=0;i<e.size();i++)
#define vi vector<ll>
inline ll rd() {
ll x=0,f=1;
char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c))x=x*10+c-'0',c=getchar();
return x*f;
}
#define d rd()
#define pb push_back
ll qp(ll a,ll b,ll p){
ll ans=1;while(b){
if(b&1)ans=ans*a%p;
a=a*a%p;b>>=1;
}return ans;
}ll t,n,m,ans,cnt;
ll a[200010];
ll c[200010];
struct node{ll x,id;}b[200010];
bool cmp(node a,node b){return a.x<b.x;}
ll s[400010];
void out(ll x){
if(x==0){putchar('0');return;}
if(x<0)putchar('-'),x=-x;
int p[100010],now=0;
while(x)p[++now]=x%10,x/=10;
for(int i=now;i>=1;i--)printf("%d",p[i]);
}
int main(){
n=d;f(i,1,n)a[i]=d,b[i]={a[i],i},c[i]=c[i-1]+a[i];
f(i,1,n)ans+=i*a[i]-c[i];
sort(b+1,b+n+1,cmp);
f(i,1,n){
if(b[i].x!=b[i-1].x){
if(b[i].x-b[i-1].x==1)cnt++;
else cnt+=2;
}a[b[i].id]=cnt;
}for(int i=n;i>=1;i--){
s[a[i]]++;
ans+=s[a[i]-1];
ans-=s[a[i]+1];
}out(ans);
return 0;
}