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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

BC div2补题以及 复习模除 逆元__BestCoder Round #78 (div.2)

發布時間:2023/12/1 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BC div2补题以及 复习模除 逆元__BestCoder Round #78 (div.2) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

 第一題沒話說 智商欠費 加老柴輔導終于過了

需要在意的是數據范圍為2的63次方-1 三個數相加肯定爆了

?? 四邊形的定義  任意邊小于其余三邊之和

換句話說就是  最長邊小于其余三邊之和

?? 這樣的話問題轉化為 最長邊依次減其余三邊的結果是否小于等于0

還有一點是題目出現0邊 即最小邊不為0 想得太多反而把0也算為合法。。。。

?? 問題只需要 sort一下 判斷a[0]==0||a[3]-a[2]-a[1]-a[0]>=0 輸出NO //存在0邊且最大邊大于其他邊之和

第二題 好多種姿勢 題目鏈接http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=683&pid=1002

官方題解

  我們令dp[i][j]表示在前i個數中,選出若干個數使得它們的gcd為j的方案數,于是只需要枚舉第i+1個數是否被選中來轉移就可以了

令第i+1個數為v,當考慮dp[i][j]的時候,我們令$dp[i+1][j] += dp[i]j,dp[i+1][gcd(j,v)] += dp[i]j

復雜度O(N*MaxV) MaxV 為出現過的數的最大值

其實有O(MaxV *log(MaxV))的做法,我們考慮記f[i]表示從這些數中選擇若干個數,使得他們的gcd是i的倍數的方案數。假如有K個數是i的倍數,則 f[i]=2^K-1,再用g[i]表示從這些數中選擇若干個數,使得他們的gcd是i的方案數,則g[i]=f[i] - g[j] (對于所有j是i的倍數)。

由調和級數可以得到復雜度為O(MaxV *log(MaxV))

DP之二維數組轉移

  我們把dp[i][j]作為考慮了第i個數GCD為j的方案數

直接gcd會超時 所以我們打個表GCD

  那么dp[i][j]+=dp[i-1][j]; dp[i][GCD[j][v[i]]]+=dp[i-1][j]; 然后就可以轉移辣;

#include<cstdio> #include<map> //#include<bits/stdc++.h> #include<vector> #include<stack> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<set> #include<queue> #include<cstdlib> #include<climits> #define PI acos(-1.0) #define INF 0x3fffffff using namespace std; typedef long long ll; typedef __int64 int64; const ll mood=1e9+7; const int64 Mod=100000007; const double eps=1e-9; const int N=1005; const int MAXN=250050; typedef int rl; inline void r(rl&num){num=0;rl f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();num*=f; } int gcd(int a,int b) {return b==0?a:gcd(b,a%b); } int v[N]; int GCD[N][N]; int64 dp[N][N]; int main() {for(int i=1;i<1001;i++){for(int j=1;j<=i;j++){GCD[i][j]=GCD[j][i]=gcd(i,j);}}int ci;r(ci);while(ci--){int n;r(n);int mx=-1;for(int i=1;i<=n;i++){r(v[i]);mx=max(mx,v[i]);dp[i][v[i]]=1;}for(int i=2;i<=n;i++){for(int j=1;j<=mx;j++){dp[i][j]+=dp[i-1][j];dp[i][j]%=Mod;dp[i][GCD[j][v[i]]]+=dp[i-1][j];dp[i][GCD[j][v[i]]]%=Mod;}}int64 ans=0;for(int i=1;i<=mx;i++){ans+=(dp[n][i]*i)%Mod;ans%=Mod;}memset(dp,0,sizeof(dp));memset(v,0,sizeof(v));printf("%I64d\n",ans);}return 0; } 二維

仔細想了一下 覺得可以優化為滾動數組 試了好久不對 最后瞎蒙

每個數都多考慮了一次 所以/2需要乘逆元 正好1e8+7是素數

Mod為素數,那么還可以根據費馬小定理得到逆元為 2的(Mod-2)次方%Mod

  即除2等于乘2的(Mod-2)次方%Mod

所以加了一個快速冪 但是優化為滾動數組后 時間增加了一丟丟 但空間大幅度減少

167578622016-04-03 12:45:34Accepted56562511MS5504K1925 BG++zxMrlc
167557982016-04-03 00:36:10Accepted56562449MS13404K1722 BG++zxMrlc

但是姿勢老感覺有問題 等wtw學長指點后我再改改 還有官方的第二個姿勢還沒有學會。。。衰

#include<cstdio> #include<map> //#include<bits/stdc++.h> #include<vector> #include<stack> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<set> #include<queue> #include<cstdlib> #include<climits> #define PI acos(-1.0) #define INF 0x3fffffff using namespace std; typedef long long ll; typedef __int64 int64; const ll mood=1e9+7; const int64 Mod=100000007; const double eps=1e-9; const int N=1005; const int MAXN=250050; typedef int rl; inline void r(rl&num){num=0;rl f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();num*=f; } int gcd(int a,int b) {return b==0?a:gcd(b,a%b); } int v[N]; int GCD[N][N]; int64 dp[N]; int main() {int64 xx=Mod-2;int64 an=1,t=2;while(xx>0){if(xx&1) an*=t;xx/=2;an%=Mod;t*=t;t%=Mod;}for(int i=1;i<1001;i++){for(int j=1;j<=i;j++){GCD[i][j]=GCD[j][i]=gcd(i,j);}}int ci;r(ci);while(ci--){int n;r(n);int mx=-1;for(int i=1;i<=n;i++){r(v[i]);mx=max(mx,v[i]);}for(int i=1;i<=n;i++){dp[v[i]]++;for(int j=1;j<=mx;j++){// dp[i][j]+=dp[i-1][j];dp[j]%=Mod;dp[GCD[j][v[i]]]+=dp[j];dp[GCD[j][v[i]]]%=Mod;}}int64 ans=0;//for(int i=1;i<=mx;i++) cout<<dp[i]<<endl;for(int i=1;i<=mx;i++){ans+=(dp[i]*i)%Mod;ans%=Mod;}memset(dp,0,sizeof(dp));memset(v,0,sizeof(v));printf("%I64d\n",ans*an%Mod);}return 0; } 滾動數組

?我們每次加入的數據會導致翻倍 所以剛才改為加完/2;

因為添加的v[i]導致的影響就是 當前位置dp[v[i]]多1 即方案數多了選自己的 所以在循環結尾-1就ok了 。。。根本不需要模除 但時間特么變大了

還是有點模糊的 不太清楚到底怎么回事。

167581632016-04-03 13:17:49Accepted56562636MS5504K1730 BG++zxMrlc

?

#include<cstdio> #include<map> //#include<bits/stdc++.h> #include<vector> #include<stack> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<set> #include<queue> #include<cstdlib> #include<climits> #define PI acos(-1.0) #define INF 0x3fffffff using namespace std; typedef long long ll; typedef __int64 int64; const ll mood=1e9+7; const int64 Mod=100000007; const double eps=1e-9; const int N=1005; const int MAXN=250050; typedef int rl; inline void r(rl&num){num=0;rl f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();num*=f; } int gcd(int a,int b) {return b==0?a:gcd(b,a%b); } int v[N]; int GCD[N][N]; int64 dp[N]; int main() {for(int i=1;i<1001;i++){for(int j=1;j<=i;j++){GCD[i][j]=GCD[j][i]=gcd(i,j);}}int ci;r(ci);while(ci--){int n;r(n);int mx=-1;for(int i=1;i<=n;i++){r(v[i]);mx=max(mx,v[i]);}for(int i=1;i<=n;i++){dp[v[i]]++;for(int j=1;j<=mx;j++){// dp[i][j]+=dp[i-1][j];dp[j]%=Mod;dp[GCD[j][v[i]]]+=dp[j];dp[GCD[j][v[i]]]%=Mod;}dp[v[i]]--;}int64 ans=0;for(int i=1;i<=mx;i++){ans+=(dp[i]*i)%Mod;ans%=Mod;}memset(dp,0,sizeof(dp));memset(v,0,sizeof(v));printf("%I64d\n",ans%Mod);}return 0; } 滾動第二次優化

?

轉載于:https://www.cnblogs.com/Geek-xiyang/p/5349677.html

總結

以上是生活随笔為你收集整理的BC div2补题以及 复习模除 逆元__BestCoder Round #78 (div.2)的全部內容,希望文章能夠幫你解決所遇到的問題。

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