方程的解数[NOI2001](meet in the middle)
题目链接:http://cogs.pro:8080/cogs/problem/problem.php?pid=304
题解:
直接搜索(枚举)复杂度为O(m^n),可以用meet in the middle降为(sqrt(m^n))。
什么是meet in the middle呢?
就是把整个搜索范围分成两部分分开搜索。
就这道题而言,我们把他分成两部分之后,可以算出每个部分的可能取值集合,然后再统计从两个集合中各取一个且和为0的方案数即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define LL long long 6 #define RI register int 7 using namespace std; 8 const int INF = 0x7ffffff ; 9 const int N = 10 ; 10 const int M = 3500000 ; 11 12 inline int read() { 13 int k = 0 , f = 1 ; char c = getchar() ; 14 for( ; !isdigit(c) ; c = getchar()) 15 if(c == '-') f = -1 ; 16 for( ; isdigit(c) ; c = getchar()) 17 k = k*10 + c-'0' ; 18 return k*f ; 19 } 20 int n, m, rk1, rk2, lv, ans ; int p[N], k[N], p1[N], k1[N], res1[M], res2[M] ; 21 22 inline int poww(int a,int b) { 23 int base = a, rres = 1 ; 24 while(b) { 25 if(b&1) rres *= base ; 26 base *= base ; b >>= 1 ; 27 } 28 return rres ; 29 } 30 void dfs(int now,int res,int *a,int &rk) { 31 if(now > lv) { 32 a[++rk] = res ; return ; 33 } 34 for(int i=1;i<=m;i++) { 35 // printf("xxx\n") ; 36 dfs(now+1,res+k1[now]*poww(i,p1[now]),a,rk) ; 37 } 38 } 39 inline void work() { 40 int j = rk2 ; 41 sort(res1+1,res1+rk1+1) ; sort(res2+1,res2+rk2+1) ; 42 for(int i=1;i<=rk1;i++) { 43 while(res1[i]+res2[j] > 0 && j) j-- ; 44 if(j <= 0) break ; 45 if(res1[i]+res2[j] < 0) continue ; 46 int cnt1 = 1, cnt2 = 1 ; 47 while(res1[i] == res1[i+1] && i < rk1) i++, cnt1++ ; 48 while(res2[j] == res2[j-1] && j > 1) j--, cnt2++ ; 49 ans += cnt1*cnt2 ; 50 } 51 } 52 53 int main() { 54 // freopen("equation1.in","r",stdin) ; 55 // freopen("equation1.out","w",stdout) ; 56 n = read(), m = read() ; 57 for(int i=1;i<=n;i++) { 58 k[i] = read(), p[i] = read() ; 59 } 60 lv = n>>1 ; 61 for(int i=1;i<=lv;i++) k1[i] = k[i], p1[i] = p[i] ; 62 dfs(1,0,res1,rk1) ; 63 for(int i=1;i<=n-lv;i++) k1[i] = k[i+lv], p1[i] = p[i+lv] ; 64 lv = (n+1)>>1 ; 65 dfs(1,0,res2,rk2) ; 66 work() ; 67 printf("%d",ans) ; 68 return 0 ; 69 }