AtCoder Beginner Contest 166 比赛人数11690 比赛开始后11分钟看到所有题
AtCoder Beginner Contest 166 E This Message Will Self-Destruct in 5s 公式推导+排列组合+统计雷同元素归属不同种类的数量
总目录详见https://blog.csdn.net/mrcrack/article/details/104454762
在线测评地址https://atcoder.jp/contests/abc166/tasks/abc166_e
第一次能在赛后20分钟内,独立AC掉E题,可喜可贺。
该题目标就是寻找满足的Aj+Ai==j-i对数,其中i!=j.
将上述公式进行变形,得到Ai+i==j-Aj.
针对样例,应用上述公式
Input:
6
2 3 3 1 3 1
Output:
3
位置 1 2 3 4 5 6
数值 2 3 3 1 3 1
Ai+i 3 5 6 5 8 7
j-Aj -1 -1 0 3 2 5
雷同的3,Ai+i有1个,j-Aj有1个,对应的组合数量有1*1=1个
雷同的5,Ai+i有2个,j-Aj有1个,对应的组合数量有2*1=2个
总的数量是1+2=3
提醒,可能会遇到雷同情况时,Ai+i==j-Aj,此时i==j,此种情况,注意扣除。
数据如何处理?请接着看
Ai+i 3 5 6 5 8 7
j-Aj -1 -1 0 3 2 5
给Ai+i系列打上标记0,j-Aj系列打上标记1,将两个数组拼成一个数组,排序后,如下
位置 1 2 3 4 5 6 7 8 9 10 11 12
数值 -1(1) -1(1) 0(1) 2(1) 3(0) 3(1) 5(0) 5(0) 5(1) 6(0) 7(0) 8(0)
Ai+i 3 5 6 5 8 7
j-Aj -1 -1 0 3 2 5
如何找排列组合需要的数据,请仔细观察
3(0) 3(1)这组数据在数值相等的基础上,出现了标记0,1
5(0) 5(0) 5(1)这组数据在数值相等的基础上,出现了标记0,1
AC代码如下
#include <cstdio>
#include <algorithm>
#define maxn 200010
#define LL long long
using namespace std;
int a[maxn],b[maxn],c[maxn],cnt,cnta,cntb;
LL sum;
struct node{
int flag;
int v;
}e[maxn<<1];
int cmp(node a,node b){
return a.v==b.v?a.flag<b.flag:a.v<b.v;//若数值相等,按标记自小到大排序
}
int main(){
int n,i,good;
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
for(i=1;i<=n;i++)b[i]=a[i]+i,c[i]=i-a[i];//计算Ai+i,j-Aj
for(i=1;i<=n;i++)
if(b[i]==c[i])sum--;//提醒,可能会遇到雷同情况时,Ai+i==j-Aj,此时i==j,此种情况,注意扣除.
for(i=1;i<=n;i++)//给Ai+i系列打上标记0,j-Aj系列打上标记1,将两个数组拼成一个数组
e[++cnt].flag=0,e[cnt].v=b[i];
for(i=1;i<=n;i++)//给Ai+i系列打上标记0,j-Aj系列打上标记1,将两个数组拼成一个数组
e[++cnt].flag=1,e[cnt].v=c[i];
sort(e+1,e+1+cnt,cmp);//排序
e[0].v=2e9,cnta=0,cntb=0,good=0;
for(i=1;i<=cnt;i++)
if(e[i-1].v==e[i].v){
if(e[i-1].flag==0&&e[i].flag==1)good=1;//参与排列组合的数据在数值相等的基础上,出现了标记0,1
if(e[i].flag==0)cnta++;//统计参与排列组合的数据中b[i]=a[i]+i的数量
else cntb++;//统计参与排列组合的数据中c[i]=i-a[i]的数量
}else{
if(good)sum+=(LL)cntb*(cnta+1);//cnta+1,+1是指加上参与排列组合的雷同数据的第一个,之前未参与计数
cnta=0,cntb=0,good=0;
}
if(good)sum+=(LL)cntb*(cnta+1);//边界处理。
printf("%lld\n",sum);
return 0;
}
试了试map的写法,代码确实够短
AC代码如下
#include <cstdio>
#include <map>
#define maxn 200010
#define LL long long
using namespace std;
int a[maxn],n;
LL ans;
map<int,int> mp;
int main(){
int i;
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
for(i=1;i<=n;i++)
if(i-a[i]>0)mp[i-a[i]]++;//记录i-a[i]的数量
for(i=1;i<=n;i++)
if(mp[a[i]+i])ans+=mp[a[i]+i];//查重
printf("%lld\n",ans);
return 0;
}