鏈接:https://www.nowcoder.com/acm/contest/215/A
來源:牛客網
題目描述
“White shores, and beyond. A far green country under a swift sunrise.”--灰魔法師
給出長度爲n的序列a, 求有多少對數對 (i, j) (1 <= i < j <= n) 滿足 ai + aj 爲完全平方數。
輸入描述:
第一行一個整數 n (1 <= n <= 105)
第二行 n 個整數 ai (1 <= ai <= 105)
輸出描述:
輸出一個整數,表示滿足上述條件的數對個數。
示例1
輸入
3
1 3 6
輸出
2
思路:首先能想到ai+aj最大和也就是2e5,同時2e5以內的平方數只有400多個,可以直接打表存下來,記爲p[i]。
然後我們把每個a[i]做標記(同時統計個數),用p[i]去掃描a[i],已知p[1],令p[1]-ai,所得差即爲另一個數aj,如果能在a[i]裏找到(即a[j]被標記),說明這個平方和p[1]成立。複雜度O(1e2*1e5)。
接下來需要考慮兩種情況:
1。完全相同的數組合:2 2 2 此時方案是3,我們標記數組應該是vis[2]=3,那麼都是相同的數字,任選兩個的方案數:C[3,2],即(n*(n-1))/2。
2.不同的數字組合:1 1 3 3 此時方案是4,標記數組vis[1]=2,vis[3]=2,直接vis[1]*vis[3]就是方案數,由於重複計算(vis[3]*vis[1]),這個情況的答案需要/2,1情況不需要。
總之就是結果統計需要考慮相同數字的情況,情況就這兩種- -。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll vis[100010],n,a[1010],pos,ans1,ans2;
ll ans;
int main()
{
pos=1;
for(ll i=1;i*i<=200000;i++)a[pos++]=i*i; //生成平方數
while(~scanf("%lld",&n))
{
memset(vis,0,sizeof(vis));
ll x;
for(ll i=1;i<=n;i++)
{
scanf("%lld",&x);
vis[x]++; //統計個數
}
ans1=ans2=0;
ll tmp;
for(ll i=1;i<pos;i++) //平方數數組
{
for(ll j=1;j<=100000;j++) //1e5以內所有數
{
if(vis[j]==0)continue;
tmp=a[i]-j;
if(tmp>100000)continue; //不合法範圍
if(tmp<=0)break; //不合法
if(vis[tmp])
{
if(tmp==j)ans1+=(vis[j]*(vis[j]-1))/2; //相同時用組合公式
else ans2+=vis[tmp]*vis[j]; //不同時直接乘
}
}
}
ans1=ans1+ans2/2;
printf("%lld\n",ans1);
}
return 0;
}