洛谷P4495 奇怪的背包 [HAOI2018] 数论
正解:數論+dp
解題報告:
傳送門!
首先看到這題,跳無數次,自然而然可以想到之前考過好幾次了的一個結論——如果只考慮無限放置i,它可以且僅可以跳到gcd(p,v[i])
舉一反三一下,如果有多個i,表示成a[i]好了,那就一定是能跳到gcd(p,v[a[1]],v[a[2]],..,v[a[n]]),因為這個太長了后面單一個gcd就指的它
挺顯然的這兒不證明了QAQ
然后這兒就相當于是問有多少種a[i]的方案能滿足gcd|gcd(p,w)
然后因為多組詢問,顯然考慮能不能預處理一個f[i]:能表示出i的集合的個數
顯然可以考慮先求f[i]:gcd恰好為i的集合個數,然后搞個f[i]=∑f[d](d|i),就求出來答案辣
然后現在就變成考慮怎么樣求出前面那個意義下的f
考慮什么情況可能對f[i]有貢獻?顯然只有i的倍數才行
所以先統計出i的倍數的個數為cnt,那就有gcd為i的倍數的數就有2cnt-1個,這里應該能get?
但是要考慮去重昂,就因為我們統計的是gcd為i的倍數的個數,所以把所有是i的倍數的再減去就得到的是gcd=i的數量了
最后把那個f[i]=∑f[d](d|i)搞下就歐克
綜上,這題就做完了
好像說得很潦草不好理解的樣子,但反正沒人看,我又懶得寫了,就這樣趴hhhh
如果居然有人看又沒看懂在下面留言就成我再重新組織下語言重構這篇題解算了,,,
然后再瞎說下細節趴QAQ
首先因為p的范圍是1e9,然后對p的所有約數都是要統計的,所以如果設數組就要開到1e9,所以顯然考慮離散化一下,但是怎么離散化還是要記下name[i]=j表示i的離散化之后對應的值,就還是要開1e9的
所以有兩種方案,一個是開個map,另一個是開兩個name數組
因為我是開了兩個nam數組而且map那個很無腦所以map那個我就不說了只大概港下name數組
就直接分類討論,隨便設定一個界限M,M的大小隨意只要是能開得下數組又沒太小就歐克
然后對d<=M的因數d直接放到name1[d]里存著,否則存到name2[p/d]
然后就做完了?應該沒什么了,其實我覺得我講得還是挺詳細的來著,,,
?
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; #define il inline #define gc getchar() #define t(i) edge[i].to #define mp make_pair #define ri register int #define rb register bool #define rc register char #define lb(x) lower_bound(st+1,st+st_cnt,x)-st #define rp(i,x,y) for(ri i=x;i<=y;++i) #define my(i,x,y) for(ri i=x;i>=y;--i) #define e(i,x) for(ri i=head[x];i;i=edge[i].nxt)const int N=1e6+10,mod=1000000007,M=50000; int n,q,p,v[N],w[N],poww[N]={1},divv[N],div_cnt,id1[M],id2[M],s[M],f[M];il int read() {rc ch=gc;ri x=0;rb y=1;while(ch!='-' && (ch<'0' || ch>'9'))ch=gc;if(ch=='-')ch=gc,y=0;while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;return y?x:-x; } il int gcd(ri gd,ri gs){return gs?gcd(gs,gd%gs):gd;} il int ask_id(ri x){return x<=M?id1[x]:id2[p/x];}int main() { // freopen("4495.in","r",stdin);//freopen("4495.out","w",stdout);n=read();q=read();p=read();rp(i,1,n)v[i]=gcd(read(),p);rp(i,1,n)poww[i]=(poww[i-1]<<1)%mod;for(ri i=1;i*i<=p;++i)if(!(p%i)){divv[++div_cnt]=i;if(i*i!=p)divv[++div_cnt]=p/i;}sort(divv+1,divv+1+div_cnt);rp(i,1,div_cnt)if(divv[i]<=M)id1[divv[i]]=i;else id2[p/divv[i]]=i;rp(i,1,n)++s[ask_id(v[i])];my(i,div_cnt,1){ri tmp1=s[i],tmp2=0;rp(j,i+1,div_cnt)if(!(divv[j]%divv[i]))tmp2=(tmp2+f[j])%mod,tmp1+=s[j];f[i]=(poww[tmp1]-1-tmp2+mod)%mod;}my(i,div_cnt,1)rp(j,1,i-1)if(!(divv[i]%divv[j]))f[i]=(f[i]+f[j])%mod;while(q--)printf("%d\n",f[ask_id(gcd(read(),p))]);return 0; } 最后放個代碼趴!?
總結
以上是生活随笔為你收集整理的洛谷P4495 奇怪的背包 [HAOI2018] 数论的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: swagger换新UI
- 下一篇: stat() /root/xxx/ind