基本是參考watashi寫的 他的容斥寫得好漂亮!!! Orz
 /**//*
題意:給出n個數ai 若di = (ai,bi),其中 x<=bi<=y,問s<=∑di<=t的方案數
n<=40 s,t<=2000 x,y<=10^9 ai<=10^6
首先di是ai的因子,枚舉di
g = (a , b ) <==> 1 = ( a/g , b/g )
然后計算[1,y]內有多少個數是滿足 1 = ( a/g , b/g ) , 用容斥做
對 a/g 分解質因數,然后答案就是 b/g - 與a/g不互素的

然后再dp求出 s<=∑di<=t 的方案數
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>

using namespace std;

const long long MOD = 1000000007LL;

vector<int> factor;

long long cal(int n, int x, int y)//很漂亮的容斥,遞歸寫的 .
  {
if( n == 0 )return y / x;
return cal( n-1 , x , y) + cal( n-1 , x * (-factor[n-1]) , y);
}
// cal (x,i) == 1 | i<=y
long long cal( int x , int y )
  {
factor.clear();
for( int g = 2; g * g <= x; g++ )
 {
if( x % g == 0)
 {
factor.push_back( g );
while( x % g == 0 ) x /= g;
}
}
if( x > 1)factor.push_back( x );
return cal( factor.size() , 1, y );
}

int main()
  {
#ifdef ONLINE_JUDGE
#else
freopen( "in" , "r" , stdin );
#endif
int n, s, t, x, y, a;
while( ~scanf( "%d%d%d%d%d", &n, &s, &t, &x, &y ) )
 {
--x;//
vector< long long > dp( t +1 , 0);
dp[0] = 1;
for(int i = 1; i<= n; i ++)
 {
scanf("%d",&a);
vector< pair< int , long long > > VG;
for( int g = 1; g * g <= a; g++ )
 {
if( a % g )continue;
int _g = a / g;
VG.push_back( make_pair( g , cal( a / g , y / g ) - cal( a / g , x / g ) ) );
if( _g != g )// g != _g
VG.push_back( make_pair( _g , cal( a / _g , y / _g ) - cal( a / _g , x / _g ) ) );
}
for( int j = t ; j >= 0; j--)//這里需要j>=0因為要對于i>0,更新dp[0] = 0!!
 {
dp[j] = 0;
for(int ii = 0; ii < VG.size(); ii++)
 {
int val = VG[ii].first ;
long long num = VG[ii].second;
if( j < val )continue;
dp[j] = ( dp[j] + dp[j-val] * num )%MOD;
}
}
}
long long ans = 0;
for( int i = s; i <= t ; i++ )
ans = ( ans + dp[i] ) % MOD;
printf("%lld\n", ans);
}
return 0;
}
|