【NOIP2015模拟11.5】Divide
Description
Input
Output
Sample Input
输入1:
4 100
4 5 2 25
输入2:
12 1
1 1 1 1 1 1 1 1 1 1 1 1
输入3:
27 360
269 154 94 221 171 154 50 210 258 358
121 159 8 47 290 125 291 293 338 248
295 160 268 227 99 4 273
Sample Output
输出1:
2
输出2:
220
输出3:
114
Data Constraint
反思&题解
比赛思路: 暴力……(居然爆0了,听说数据long long也会爆,打gcd才行)
正解思路: 先拿一个数组存一下p的因数,因为质因子
是最接近且大于p的结果,所以p的因子最多有
个,三重循环复杂度
显然不会爆,
之后我们再拿一个桶记录每个a[i]与p的gcd出现的次数,之后枚举p的每个因子,
设分别为i,j,k,有5种情况
1. 当
时,就是在p的因子i里面选择3个,即
2. 当 时,就是在p的因子i里面选择2个,在k里面选择1个,即
3. 当
时,参考情况2
4. 当
时,也参考情况2
5. 当
时,就是在p的因子i,j,k种各选择一个,即
最后因为这题时不带模数的,所以费马小定理求组合数就用不了,我们就可以将式子化简来求,化简我在这就不写了,留给大家思考的空间,实在想不到就看code吧
反思: 思维很重要,转化题目有时候时AC的关键
CODE
#include<bits/stdc++.h>
using namespace std;
long long n,p,yz[1000005],tong[1000005],ans;
long long gcd(long long x,long long y)
{
if (x%y==0) return y;
else return gcd(y,x%y);
}
int main()
{
freopen("divide.in","r",stdin);
freopen("divide.out","w",stdout);
scanf("%lld%lld",&n,&p);
long long i;
for (i=1;i<=p;i++)
if (p%i==0) yz[++yz[0]]=i;
for (i=1;i<=n;i++)
{
long long x;
scanf("%lld",&x);
tong[gcd(x,p)]++;
}
long long j,k;
for (i=1;i<=yz[0];i++)
{
for (j=i;j<=yz[0];j++)
{
for (k=j;k<=yz[0];k++)
{
if (yz[i]*yz[j]*yz[k]%p==0)
{
if (i==j && j==k) ans+=tong[yz[i]]*(tong[yz[j]]-1)*(tong[yz[k]]-2)/6;
else if (i==j) ans+=tong[yz[i]]*(tong[yz[j]]-1)*tong[yz[k]]/2;
else if (j==k) ans+=tong[yz[j]]*(tong[yz[k]]-1)*tong[yz[i]]/2;
else if (i==k) ans+=tong[yz[i]]*(tong[yz[k]]-1)*tong[yz[j]]/2;
else ans+=tong[yz[i]]*tong[yz[j]]*tong[yz[k]];
}
}
}
}
printf("%lld\n",ans);
return 0;
}