【数位DP】好数(jzoj 1521)
生活随笔
收集整理的這篇文章主要介紹了
【数位DP】好数(jzoj 1521)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
好數(shù)
jzoj 1521
題目大意:
定義好數(shù)為轉(zhuǎn)換為二進(jìn)制后,有至少三個連續(xù)的位相同的數(shù),現(xiàn)在要求一個范圍內(nèi)的好數(shù)個數(shù)
樣例輸入
0 16樣例輸出
5數(shù)據(jù)范圍限制
0 <= Low <= UP <= 2147483647
提示
提示:
對于50%測試,0 <= Low <= UP <= 100000。
解題思路:
我們可以用前綴和來求,就把問題轉(zhuǎn)換為了前n個數(shù)中好數(shù)的個數(shù)
它讓我們求好數(shù),但因為好數(shù)特別難求,所以我們可以求‘壞數(shù)’,就是沒有連續(xù)三個位是一樣的數(shù)
我們先用數(shù)位DP求出多少位以什么開頭的壞數(shù)總數(shù)
然后我們把他分位數(shù)小于n的位數(shù)的和等于n的位數(shù)的
小于的:
我們就可以直接用已經(jīng)求出來的壞數(shù)總數(shù),然后分為不同位數(shù)的直接加就行了
如1…1100100先分為1位,2位,3位,4位,5位,6位的類型
等于的:
就從大到小把1變成0,這樣就一定小于n了,然后分別計算
最后還要計算n
然后用n減去壞數(shù)的個數(shù)就得到了好數(shù)的個數(shù)了
代碼:
#include<cstdio> #include<cstring> #include<iostream> #define ll long long using namespace std; ll a,b,s[40],f[40][5][5]; ll js(ll now) {ll sum=1;for (int i=now-1;i>0;--i)sum+=f[i][1][0]+f[i][1][1];//小于的(第一類)for (int i=now-1;i>0;--i){if (s[i]==1)if (s[i+1]==1||s[i+2]==1||i==now-1)//把1改為0sum+=f[i+1][s[i+1]][0];相加if (s[i]==s[i+1]&&s[i+1]==s[i+2]&&i!=now-1)//判斷是不是已經(jīng)成為了好數(shù)了{sum--;break;}}return sum; } ll ans(ll dep) {if (dep<=0) return 0;ll l=dep,tot=0;memset(s,0,sizeof(s));while (l) s[++tot]=l&1,l>>=1;//轉(zhuǎn)二進(jìn)制return dep-js(tot);//求好數(shù) } int main() {f[1][1][0]=1;f[1][0][1]=1;for (int k=2;k<=35;++k){f[k][0][0]=f[k-1][0][1];//數(shù)位DPf[k][0][1]=f[k-1][1][1]+f[k-1][1][0];f[k][1][0]=f[k-1][0][0]+f[k-1][0][1];f[k][1][1]=f[k-1][1][0];}scanf("%lld %lld",&a,&b);printf("%lld",ans(b)-ans(a-1));//前綴和求職 } 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的【数位DP】好数(jzoj 1521)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 江南春的意思是什么
- 下一篇: 纪中C组模拟赛总结(2019.7.5)