基本是参考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; }
|