日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

HDU - 4507 吉哥系列故事——恨7不成妻(数位dp)

發布時間:2024/4/11 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HDU - 4507 吉哥系列故事——恨7不成妻(数位dp) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接:點擊查看

題目大意:給出閉區間[l,r],求出區間內與7不沾邊的數的平方和

與7有關的條件:

  • 整數中某一位是7;
  • 整數的每一位加起來的和是7的整數倍;?
  • 這個整數是7的整數倍;?
  • 題目分析:拋去平方和,如果改成統計有多少個符合條件的數字,那就是傳統的數位dp了,只需維護一個dp[pos][sum1][sum2]即可,pos表示位數,sum1表示第二個條件的余數,sum2表示第三個條件的余數,向下傳遞的時候按照規則模擬即可,如果不懂的話看一眼代碼就好了

    下面重點講一下如何處理平方和,關于維護數位dp中的平方和,我看到網上一個很巧妙的方法,需要維護三個值,分別是符合條件的數量,截止到當前位的符合條件的數值總和,截止到當前位的符合條件的平方和,為了方便傳遞,這里用一個結構體封裝一下。

    那么下面先介紹參數變量,數量用cnt表示,總和用sum表示,平方和用powsum表示,然后按照傳統數位dp的思想,我們需要用到回溯法,從最高位先下傳到最低位然后回溯,隨后自底向上不斷傳遞狀態,那么我們可以假設兩個結構體:ans和temp,ans表示當前遞歸函數正在處理的數據,temp表示已經從底部返回上來的數據,即已經處理完成的數據,返回到ans中進一步處理。

    如果不太理解ans和temp的關系,我再進一步說明一下,舉個例子,ans正在處理當前數位從0~9的數字,每個數字下傳后返回上來的結果,那么temp就表示每個數字下傳返回上來的結果,也就是說ans比temp高一級。

    大概是這個樣子的一個關系

    然后就是需要處理cnt,sum和powsum這三個參數該如何傳遞了

    關于cnt,就是最基礎的數位dp的傳遞思路,只需要不斷累加就行,這里不過贅述,直接寫出轉移方程:

    ans.cnt+=temp.cnt;

    關于sum,我們首先可以先將當前表示的數字重構一下,表示為,i表示為最高位,x表示為剩余的低位部分,不過這只是表示的一個符合條件的數的sum,我們目前一共有cnt個數符合條件,所以這個結果需要乘以cnt,那么就顯而易見了,x就相當于已經處理完的上一級返回的sum的值了,想一想是不是?為了表示方便,我們用一個輔助數組p,來存儲每一位的進制,即p[1]=1,p[2]=10,p[3]=100以此類推,這樣就可以表示為

    ans.sum+=(i*p[pos]+x)*temp.cnt;

    化簡一下:

    ans.sum+=i*p[pos]*temp.cnt+temp.sum;

    還剩下一個平方和,這個的話需要在紙上化簡一下,是個完全平方公式,接著上面的重構的數字來說,平方和就是求這個結果,但直接求肯定不好求,需要化簡一下,展開平方后為:最后別忘了整體乘上cnt就好,那么初始的公式為:

    ans.powsum+=(i*i*p[pos]*p[pos]+x*x+2*i*p[pos]*x)*temp.cnt;

    把temp.cnt乘進去消掉x:

    ans.powsum+=i*i*p[pos]*p[pos]*temp.cnt+temp.powsum+2*i*p[pos]*temp.sum;

    這樣轉移方程就都有了,再說一下為什么temp.cnt與x相遇可以消去吧,因為我們一開始也提到了,temp.sum和temp.powsum指的是從temp中傳遞上來的結果,就是已經計算完畢的結果,已經乘過cnt了,而x表示的是上一層中關于一個可行數字的總和和平方和,所以這一層的x遇到cnt就可以用上一層的sum和powsum來替換了。

    還有一點需要注意,在計算的過程中要實時取模,代碼中的具體實現是上述轉移方程穿插了無數個mod后的成品,及其難看,所以不用過多在意美觀性了。。在計算過程中cnt,sum和powsum都會爆int,所以記得開long long,最后就是輸出結果的時候,因為取模的原因,可能solve(b)比solve(a-1)要小,所以記得對負數取模:

    (solve(b)-solve(a-1)+mod)%mod

    上代碼了:

    #include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #include<stack> #include<queue> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=(1<<21)+100;struct Node {LL cnt,sum,powsum;//符合條件的個數,截止到目前為止的總和,截止到目前為止的平方和Node(){cnt=sum=powsum=0;} }dp[20][7][7];//dp[pos][sum%mod][mod]LL b[20];LL p[20];const int mod=1e9+7;Node dfs(int pos,int sum,int sum2,bool limit) {if(pos==0){Node temp;if(sum%7==0||sum2%7==0)temp.cnt=0;elsetemp.cnt=1;return temp;}if(!limit&&dp[pos][sum][sum2].cnt!=-1)return dp[pos][sum][sum2];int up=limit?b[pos]:9;Node ans;for(int i=0;i<=up;i++){if(i==7)continue;Node temp=dfs(pos-1,(sum+i)%7,(sum2*10+i)%7,limit&&i==b[pos]);ans.cnt=(ans.cnt+temp.cnt)%mod;ans.sum=(ans.sum+(p[pos]*i%mod*temp.cnt%mod)+temp.sum)%mod;ans.powsum=(ans.powsum+i*i*p[pos]%mod*p[pos]%mod*temp.cnt%mod+temp.powsum+2*i*p[pos]%mod*temp.sum%mod)%mod;}if(!limit)dp[pos][sum][sum2]=ans;return ans; }LL solve(LL n) {int cnt=0;while(n){b[++cnt]=n%10;n/=10;}return dfs(cnt,0,0,true).powsum; }int main() { // freopen("input.txt","r",stdin);int w;cin>>w;memset(dp,-1,sizeof(dp));p[1]=1;for(int i=2;i<20;i++)p[i]=p[i-1]*10%mod;while(w--){LL a,b;cin>>a>>b;cout<<(solve(b)-solve(a-1)+mod)%mod<<endl;}return 0; }

    ?

    總結

    以上是生活随笔為你收集整理的HDU - 4507 吉哥系列故事——恨7不成妻(数位dp)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。