[ NOI 2001 ] 方程的解數

$\$ios

$Description$


已知一個 $N$ 元高次方程: $$ k_1x_1^{p_1}+k_2x_2^{p_2}+...+k_nx_n^{p_n}=0 $$ 要求全部的 $x_i$ 取值範圍爲$[1,m]$且爲整數,求方程的解數。git

  • $n\le 6,m\le 150$

$\$學習

$Solution$


發現 $150^6$ 複雜度爆炸,天然能想到折半搜。url

先搜前一半的全部可能的答案,存進哈希表裏,而後搜後一半的答案,在哈希表裏查相反數,若是存在就累加上個數。spa

而後 $map$ 就被卡 $T$ 了。其實這篇題解是哈希表學習筆記.......net

哈希表能夠理解爲一種相似多頭鏈表的結構。當答案很大可是答案的個數並非不少的時候選擇。code

每次獲得一個答案先將他縮小在$[1,mod]$範圍內,而後查詢這個值是否有存儲過,若是有就累加計數器。ip

若是沒有的話操做就頗有意思了。考慮到可能會有多個數通過模運算獲得的答案相同,因此不能直接在模運算所得答案處存儲這個數,而要像鄰接表同樣,由這個答案向真正的數連一條邊,邊權就是個數。get

而後查值得時候操做就和遍歷鄰接表同樣了。由於模數選擇質數,因此獲得的答案分佈仍是很均勻的,單次查詢和累加複雜度都接近$\text O(1)$。string

$\$

$Code$


#include<map>
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define R register
#define gc getchar
#define mod 6893911
using namespace std;

inline int rd(){
  int x=0; bool f=0; char c=gc();
  while(!isdigit(c)){if(c=='-')f=1;c=gc();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
  return f?-x:x;
}

int n,m,t[10],k[10],ans;

struct hashtable{

  int hd[mod+2],tot;

  struct edge{int w,to,nxt;}e[4000000];

  inline void add(int u,int v){
    e[++tot].to=v; e[tot].w=1;
    e[tot].nxt=hd[u]; hd[u]=tot;
  }

  inline int find(int x){
    int tmp=(x%mod+mod)%mod;
    if(!hd[tmp]) return -1;
    for(R int i=hd[tmp],v;i;i=e[i].nxt)
      if((v=e[i].to)==x) return e[i].w;
    return -1;
  }

  inline void insert(int x){
    int tmp=(x%mod+mod)%mod;
    if(!hd[tmp]) add(tmp,x);
    else{
      for(R int i=hd[tmp],v;i;i=e[i].nxt)
        if((v=e[i].to)==x){++e[i].w;return;}
      add(tmp,x);
    }
  }

}s;

inline int qpow(int x,int t){
  int res=1;
  while(t){
    if(t&1) res*=x;
    x*=x; t>>=1;
  }
  return res;
}

void dfsl(int p,int sum){
  if(p>n/2){s.insert(sum);return;}
  for(R int i=1;i<=m;++i) dfsl(p+1,sum+k[p]*qpow(i,t[p]));
}

void dfsr(int p,int sum){
  if(p>n){
    int tmp=s.find(-sum);
    if(tmp>0) ans+=tmp; return;
  }
  for(R int i=1;i<=m;++i) dfsr(p+1,sum+k[p]*qpow(i,t[p]));
}

int main(){
  n=rd(); m=rd();
  for(R int i=1;i<=n;++i) k[i]=rd(),t[i]=rd();
  dfsl(1,0); dfsr(n/2+1,0);
  printf("%d\n",ans);
  return 0;
}
相關文章
相關標籤/搜索