Linking
题意:
给定一个长度为 n 的数列和数字 m,判断有多少个数对
(
i
,
k
)
(i,k)
(i,k) 满足:
a
[
i
]
∗
a
[
i
+
m
]
∗
a
[
i
+
2
m
]
∗
.
.
.
∗
a
[
i
+
k
m
]
a[i]*a[i+m]*a[i+2m]*...*a[i+km]
a[i]∗a[i+m]∗a[i+2m]∗...∗a[i+km]为质数。
思路:
若干个数相乘为质数,那么只有一个数为质数,其余数都为1。
所以
- 对于 a[i] 为质数,就需要计算后面连续的 a[i+km] 为1的个数。
- 对于 a[i] 为1,那么需要找到后面连续的 a[i+km] 的个数,保证 a[i+km] 中只有一个质数。
那么
如果 a[i] 为质数,那么其后面的满足的连续的1可以作贡献,同时前面连续的1也可以作贡献。
假设该质数位置前面连续的1为 cnt1 个,后面连续的1为 cnt2 个,那么通过这个质数得到的数对个数就为
c
n
t
2
+
c
n
t
1
∗
(
c
n
t
2
+
1
)
cnt2 + cnt1*(cnt2+1)
cnt2+cnt1∗(cnt2+1)。
Code:
const int N = 1000020, mod = 1e9+7;
int T, n, m;
int a[N], prim[N];
int f[N];
void init() //埃式筛
{
f[0] = f[1] = 1;
n=1e6+1;
for(int i=2;i<=n;i++)
{
if(f[i]) continue;
else
{
for(int j=i+i;j<=n;j+=i) f[j]=1;
}
}
}
signed main(){
Ios;
init();
cin>>T;
while(T--)
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
int ans=0;
for(int i=1;i<=n;i++)
{
int cnt1=0, cnt2=0;
if(!f[a[i]])
{
for(int j=i+m;j<=n;j+=m){
if(a[j]==1) cnt2++;
else break;
}
for(int j=i-m;j>=1;j-=m){
if(a[j]==1) cnt1++;
else break;
}
}
ans+=cnt2+cnt1*(cnt2+1);
}
cout<<ans<<endl;
}
return 0;
}
关键是要想到这个性质:
若干个数相乘为质数,那么其中只有一个质数,其余都是1。