cf900 D. Unusual Sequences(容斥+dp+数论)
题意:
求gcd为 m 且和为 n 的不同数组的数量取模。
\(1\le n,m\le 1e9\)
思路:
若 n 不是 m 的倍数,则答案为0。
否则,把 n 看成 n/m 个 m 之和。由隔板法,和为 n 且元素均为 m 的倍数的不同数组有 \(2^{n/m+1}\) 个,记为 \(dp(1)\)
但是gcd为m就要求数组中的元素均是m的倍数,但不是2m、3m、4m等的倍数,所以要用容斥
一个数的因子总数不会很多,可以n^2 dp:
从大到小考虑n的所以形如km的因子,容斥更新dp
const int MOD = 1e9 + 7;
int n, m;
int qmi(int t, int k, int p=MOD)
{
int res = 1;
while (k)
{
if (k&1) res = (ll)res * t % p;
t = (ll)t * t % p; k >>= 1;
}
return res;
}
void del(int &x, int y) { x-=y; if(x<0)x+=MOD; }
vector<int> ve;
void getMdivs(int n)
{
for(int i = 1; i <= sqrt(n); i++)
if(n % i == 0) //n的形如km的因子
{
if(i % m == 0) ve.pb(i);
if(i != n/i && (n/i) % m == 0) ve.pb(n/i);
}
}
main()
{
cin >> m >> n;
if(n % m) return puts("0"), 0;
getMdivs(n);
sort(all(ve));
vector<int> dp(ve.size());
for(int i = dp.size() - 1; i >= 0; i--)
{
dp[i] = qmi(2, n / ve[i] - 1);
for(int j = i + 1; j < dp.size(); j++)
if(ve[j] % ve[i] == 0) //容斥,减去倍数
del(dp[i], dp[j]);
}
cout << dp[0];
}

浙公网安备 33010602011771号