题解:P11556 [ROIR 2016 Day 2] 超级跳棋
原本以为是组合数学,结果打了半天发现是模拟加前缀和优化。
题目链接
传送门
简略版:给定
显然,对于每个数有四种类型取法。
- A A A
- A A B
- A B B
- A B C
首先,我们用
第一种:因为三个数相同,位置与最终结果无关,只要
第二种:维护一个上界
第三种:用
第四种:当第
Code
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
#define f(n) for(int i=1;i<=n;i++)
#define ll long long
ll n,k,a[100001],sj,nd[100001];
ll num[100001],l;
ll ans;
int main()
{
cin>>n>>k;
f(n)cin>>a[i];
sort(a+1,a+1+n);
f(n)if(a[i]!=a[i-1])num[++l]=1,a[l]=a[i];
else num[l]++;
f(l)if(num[i]>=2)nd[i]=nd[i-1]+1;
else nd[i]=nd[i-1];
f(l)
{
if(num[i]>=3)ans++;//情况一
while(a[sj]<=k*a[i]&&sj<=l)sj++;//维护上界
if(num[i]>=2)ans+=3*(sj-i-1);//情况二
ans+=3*(nd[sj-1]-nd[i]);//情况三
if(sj-i>2)ans+=3*(sj-i-1)*(sj-i-2);//情况四
}
cout<<ans;
return 0;
}
综上,不算排序复杂度为
ps:记得排序(其实不排序直接