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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

蓝桥备赛第三周 倍增+贪心+素数+约数

發布時間:2024/10/8 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 蓝桥备赛第三周 倍增+贪心+素数+约数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 0X06倍增
    • 天才ACM(有空再做)
  • 0X07貪心
    • 防曬
      • 將乳液按SPF從大到小,牛按minSPF從大到小排序
        • 牛客有個題解都從小到大也過了
      • 原理
    • 畜欄預定
      • ~~按結束時間從小到大排~~
      • 按開始時間排,這樣才是模擬
      • 建一個數組表示畜欄,存放改數組當前的牛
      • 數據太大可能會過不了,可以換成堆,或者用queue來模擬畜欄位
      • 另外sort可以不寫cmp而把大小比較的代碼寫到結構體里,和map與pair那時一樣
    • 雷達設備
      • 問題轉化:每個島(建筑物),在x軸上有個能檢測到它的區間----->給定N個區間,在x軸上放n個點,讓每個區間都有點,求最小n
        • 那么按左端點從小到大排,每個都放到右端點上,用一個變量存當前最靠右的雷達,
          • 問題:如圖怎么辦
          • 雖然存的最右邊的坐標,但并不是就放在最右面了,而是存在交集,跑下面的公式,可以用同一個管轄,就可以放在交集的最右面(如果多個的話,刷新后是這幾個區間交集的最右面)
          • pos = min(r[i],pos)
        • 另:沒想出來咋不用double,也沒有用int 的題解,都是double
        • 另外y不能大于d
    • 國王游戲
      • 思路
        • 按乘積從大到小(先大膽猜想,然后試著征證)
      • 高精度
        • [高精度vector版 視頻](https://www.acwing.com/video/91/)
    • 給樹染色
      • 先染權值大的?---不行
      • 思路
      • 題解視頻: 把合并想成抬高
  • 0x31質數
    • 質數篩
    • 線性篩
    • 質因數分解
      • 輪除里藏著素數篩
    • 質數距離
      • 1-R的質數全求是不可能的,
      • 只需要L-R之間的且很小,所以,求到根號R就行,把L-R之間的合數標出來
        • ///從sqrt(L)開始算是不行的
        • 這個原理是一樣的,但是用的數組太大,應該改成兩個新的小數組a[0]代表L,a[1]代表L+1,就能過了
    • 階乘分解
      • 這道題很快樂,唯一就是數很大,所以只判斷質因子
        • 另外n的階乘的質因子不會超過n,所以就直接只計算相應的就可以啦
        • 還有就是不能直接求出來階乘,必炸,從1~n每個數求就好(對于每個質因子)
        • 但這樣還是要遍歷,所以要用離散數學的一個公式
  • 0x32約數
    • 定理三個推論
    • 單個數正約數集合--試除法(從1除到根號n)
      • 推論,約束個數上限為2倍根號n
    • 1~n 每個數的正約數集合-----倍數法(乘出來誰給誰)(不要重復)
      • 推論
    • 反素數
      • 這道題是數學推導出約束,解法是深搜
    • 余數之和
      • 這個題算法短到離譜,推導難到離譜,直接看大佬的吧
    • 最大公約和最小公倍一些定理
    • hankson的趣味題
      • 法一:
        • 搜索算法:深搜
    • 互質與歐拉函數
      • 性質
    • 可見的點
      • 這里的歐拉函數是類似素數篩的(簡單解法)

0X06倍增

天才ACM(有空再做)

https://www.acwing.com/problem/content/111/

0X07貪心

防曬

有C頭奶牛進行日光浴,第i頭奶牛需要minSPF[i]到maxSPF[i]單位強度之間的陽光。 每頭奶牛在日光浴前必須涂防曬霜,防曬霜有L種,涂上第i種之后,身體接收到的陽光強度就會穩定為SPF[i],第i種防曬霜有cover[i]瓶。 求最多可以滿足多少頭奶牛進行日光浴。 輸入格式 第一行輸入整數C和L。 接下來的C行,按次序每行輸入一頭牛的minSPF和maxSPF值,即第i行輸入minSPF[i]和maxSPF[i]。 再接下來的L行,按次序每行輸入一種防曬霜的SPF和cover值,即第i行輸入SPF[i]和cover[i]。 每行的數據之間用空格隔開。 輸出格式 輸出一個整數,代表最多可以滿足奶牛日光浴的奶牛數目。 數據范圍 1≤C,L≤2500, 1≤minSPF≤maxSPF≤1000, 1≤SPF≤1000 輸入樣例: 3 2 3 10 2 5 1 5 6 2 4 1 輸出樣例: 2

將乳液按SPF從大到小,牛按minSPF從大到小排序

牛客有個題解都從小到大也過了

原理


畜欄預定

有N頭牛在畜欄中吃草。 每個畜欄在同一時間段只能提供給一頭牛吃草,所以可能會需要多個畜欄。 給定N頭牛和每頭牛開始吃草的時間A以及結束吃草的時間B,每頭牛在[A,B]這一時間段內都會一直吃草。 當兩頭牛的吃草區間存在交集時(包括端點),這兩頭牛不能被安排在同一個畜欄吃草。 求需要的最小畜欄數目和每頭牛對應的畜欄方案。 輸入格式 第1行:輸入一個整數N。 第2..N+1行:第i+1行輸入第i頭牛的開始吃草時間A以及結束吃草時間B,數之間用空格隔開。 輸出格式 第1行:輸入一個整數,代表所需最小畜欄數。 第2..N+1行:第i+1行輸入第i頭牛被安排到的畜欄編號,編號是從1開始的 連續 整數,只要方案合法即可。 數據范圍 1≤N≤50000, 1≤A,B≤1000000 輸入樣例: 5 1 10 2 4 3 6 5 8 4 7 輸出樣例: 4 1 2 3 2 4

按結束時間從小到大排

按開始時間排,這樣才是模擬

建一個數組表示畜欄,存放改數組當前的牛

數據太大可能會過不了,可以換成堆,或者用queue來模擬畜欄位

另外sort可以不寫cmp而把大小比較的代碼寫到結構體里,和map與pair那時一樣

struct range{int l,r,w;bool operator<(const range &w)const{return l<w.l;} }range[N]; #include <iostream> #include<bits/stdc++.h> using namespace std; typedef long long ll; #define maxn 50006 struct cow{int A=0;int B=0;int lanhao=0;int num; }cows[maxn],lan[maxn]; int cmp(cow &a,cow &b) {if(a.A!=b.A){return a.A<b.A;}return a.B<b.B; } int cmp2(cow &a,cow &b)///將順序排回 {return a.num<b.num; } int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int n;cin>>n;for(int i=1;i<=n;i++){cin>>cows[i].A>>cows[i].B;cows[i].num=i;}sort(cows+1,cows+n+1,cmp);int ans=1;for(int i=1;i<=n;i++){int flag=0;for(int j=1;j<=ans;j++){if(lan[j].B<cows[i].A)///包括端點{flag=1;///找到空的了lan[j]=cows[i];cows[i].lanhao=j;break;}}if(flag==0)///沒找到,加一個{ans++;lan[ans]=cows[i];cows[i].lanhao=ans;}}sort(cows+1,cows+n+1,cmp2);cout<<ans<<endl;for(int i=1;i<=n;i++){cout<<cows[i].lanhao<<endl;}return 0; }

雷達設備

假設海岸是一條無限長的直線,陸地位于海岸的一側,海洋位于另外一側。 每個小島都位于海洋一側的某個點上。 雷達裝置均位于海岸線上,且雷達的監測范圍為d,當小島與某雷達的距離不超過d時,該小島可以被雷達覆蓋。 我們使用笛卡爾坐標系,定義海岸線為x軸,海的一側在x軸上方,陸地一側在x軸下方。 現在給出每個小島的具體坐標以及雷達的檢測范圍,請你求出能夠使所有小島都被雷達覆蓋所需的最小雷達數目。 輸入格式 第一行輸入兩個整數n和d,分別代表小島數目和雷達檢測范圍。 接下來n行,每行輸入兩個整數,分別代表小島的x,y軸坐標。 同一行數據之間用空格隔開。 輸出格式 輸出一個整數,代表所需的最小雷達數目,若沒有解決方案則所需數目輸出“-1”。 數據范圍 1≤n≤1000 輸入樣例: 3 2 1 2 -3 1 2 1 輸出樣例: 2

問題轉化:每個島(建筑物),在x軸上有個能檢測到它的區間----->給定N個區間,在x軸上放n個點,讓每個區間都有點,求最小n

那么按左端點從小到大排,每個都放到右端點上,用一個變量存當前最靠右的雷達,

問題:如圖怎么辦
雖然存的最右邊的坐標,但并不是就放在最右面了,而是存在交集,跑下面的公式,可以用同一個管轄,就可以放在交集的最右面(如果多個的話,刷新后是這幾個區間交集的最右面)
pos = min(r[i],pos)

另:沒想出來咋不用double,也沒有用int 的題解,都是double

另外y不能大于d

#include <iostream> #include<bits/stdc++.h> using namespace std; typedef long long ll; #define maxn 1005 double pos=maxn; struct point{double l;double r;bool operator<(const point &a)const{return l<a.l;}}points[maxn];int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int n,d;double x,y;double duanbian;//減小計算量,開一次根號就行了cin>>n>>d;for(int i=1;i<=n;i++){cin>>x>>y;if(y>d){cout<<-1;return 0;}duanbian=sqrt(d*d-y*y);points[i].l=x-duanbian;points[i].r=x+duanbian;}sort(points+1,points+n+1);///區間按左從小到大排int ans=1;pos=min(pos,points[1].r);for(int i=2;i<=n;i++){if(pos<points[i].l){ans++;pos=points[i].r;}else{pos=min(pos,points[i].r);}}cout<<ans;return 0; }

國王游戲

恰逢 H 國國慶,國王邀請 n 位大臣來玩一個有獎游戲。 首先,他讓每個大臣在左、右手上面分別寫下一個整數,國王自己也在左、右手上各寫一個整數。 然后,讓這 n 位大臣排成一排,國王站在隊伍的最前面。 排好隊后,所有的大臣都會獲得國王獎賞的若干金幣,每位大臣獲得的金幣數分別是: 排在該大臣前面的所有人的左手上的數的乘積除以他自己右手上的數,然后向下取整得到的結果。 國王不希望某一個大臣獲得特別多的獎賞,所以他想請你幫他重新安排一下隊伍的順序,使得獲得獎賞最多的大臣,所獲獎賞盡可能的少。 注意,國王的位置始終在隊伍的最前面。 輸入格式 第一行包含一個整數 n,表示大臣的人數。 第二行包含兩個整數 a 和 b,之間用一個空格隔開,分別表示國王左手和右手上的整數。 接下來 n 行,每行包含兩個整數 a 和 b,之間用一個空格隔開,分別表示每個大臣左手和右手上的整數。 輸出格式 輸出只有一行,包含一個整數,表示重新排列后的隊伍中獲獎賞最多的大臣所獲得的金幣數。 數據范圍 1≤n≤1000 0<a,b<10000 輸入樣例: 3 1 1 2 3 7 4 4 6 輸出樣例: 2

思路

按乘積從大到小(先大膽猜想,然后試著征證)


#include <iostream> #include<bits/stdc++.h> using namespace std; typedef long long ll; #define maxn 10006 ///國王是0,最前面 ///max獎賞最小化 struct ren{ int l=0; int r=0; int chengji=0; bool operator<(const ren &a)const{return chengji<a.chengji; } }rens[maxn]; ///左手大,盡可能往右,右手大,盡可能往右 int main() {int n;cin>>n;for(int i=0;i<n+1;i++){cin>>rens[i].l>>rens[i].r;rens[i].chengji=rens[i].l*rens[i].r;}///大臣從1到nsort(rens+1,rens+n+1);double maxjiang=0;ll zuo=1;for(int i=1;i<=n;i++){zuo*=rens[i-1].l;maxjiang=max(maxjiang,(zuo*1.0/rens[i].r));}cout<<(ll)maxjiang;return 0; }

高精度

https://www.acwing.com/solution/content/855/
需要BIGN模板

高精度vector版 視頻


給樹染色

一顆樹有 n 個節點,這些節點被標號為:1,2,3…n,每個節點 i 都有一個權值 A[i]。 現在要把這棵樹的節點全部染色,染色的規則是: 根節點R可以隨時被染色;對于其他節點,在被染色之前它的父親節點必須已經染上了色。 每次染色的代價為T*A[i],其中T代表當前是第幾次染色。 求把這棵樹染色的最小總代價。 輸入格式 第一行包含兩個整數 n 和 R ,分別代表樹的節點數以及根節點的序號。 第二行包含 n 個整數,代表所有節點的權值,第 i 個數即為第 i 個節點的權值 A[i]。 接下來n-1行,每行包含兩個整數 a 和 b ,代表兩個節點的序號,兩節點滿足關系: a 節點是 b 節點的父節點。 除根節點外的其他 n-1 個節點的父節點和它們本身會在這 n-1 行中表示出來。 同一行內的數用空格隔開。 輸出格式 輸出一個整數,代表把這棵樹染色的最小總代價。 數據范圍 1≤n≤1000, 1≤A[i]1000 輸入樣例: 5 1 1 2 1 2 4 1 2 1 3 2 4 3 5 輸出樣例: 33

先染權值大的?—不行

思路


題解視頻: 把合并想成抬高


#include <iostream> #include<bits/stdc++.h> using namespace std; typedef long long ll; #define maxn 1005 struct Node{int father,mysize,sum;/// 權值 父節點 本組元素個數double avg;///點的平均值 }nodes[maxn]; int n,root;///root是根節點序號 int finder(){///找當前avg最大的節點double avg=0;int res=-1;for(int i=1;i<=n;i++){if(i!=root&&nodes[i].avg>avg){avg=nodes[i].avg;res=i;}}return res; } int main() {while(cin>>n>>root){if(n==0&&root==0){break;}int ans=0;for(int i=1;i<=n;i++){cin>>nodes[i].sum;nodes[i].avg = nodes[i].sum;///初始值先都是權值nodes[i].mysize = 1;ans+= nodes[i].sum;}for (int i = 0; i < n - 1; i ++ ){int a, b;cin >> a >> b;nodes[b].father = a;}for (int i = 0; i < n - 1; i ++ ){int p = finder();///權值最大點int f = nodes[p].father;///找父節點ans += nodes[p].sum * nodes[f].mysize;///當前點是緊挨著父節點上色,所以是///v*(s(父節點上色號)+1),不用加一,因為上面全都提前加了一遍nodes[p].avg = -1;///父節點抹掉,合并了for (int j = 1; j <= n; j ++ )if (nodes[j].father == p)nodes[j].father = f;///當前點的所有兒子給當前點的父親nodes[f].sum += nodes[p].sum;nodes[f].mysize += nodes[p].mysize;nodes[f].avg = (double)nodes[f].sum / nodes[f].mysize;}cout << ans << endl;}return 0; }

0x31質數

質數篩


int v[maxn]; void primes(int n) {memset(v,0,sizeof(v));for(int i=2;i<=n;i++){if(v[i])continue;///是合數for(int j=i;j<=n/i;j++){v[i*j]=1;}} }

線性篩

int v[maxn],prime[maxn]; void primes(int n) {memset(v,0,sizeof(v));//最小質因子int m=0;//質數數量for(int i=2;i<=n;i++){if(v[i]==0){///i是質數v[i]=i;prime[++m]=i;}///素數篩是只對質數不斷乘到n///線性篩是每個數都乘已有的質數for(int j=1;j<=m;j++){///當前數i有比prime[j]更小的質因子///(只乘不比自己大的質數)///或者超出n的范圍if(prime[j]>v[i]||prime[j]>n/i){break;}///prime[j]是合數i*prime[j]的最小質因子v[i*prime[j]]=prime[j];}} }

質因數分解

輪除里藏著素數篩


質數距離

給定兩個整數L和U,你需要在閉區間[L,U]內找到距離最接近的兩個相鄰質數C1和C2(即C2-C1是最小的),如果存在相同距離的其他相鄰質數對,則輸出第一對。同時,你還需要找到距離最遠的兩個相鄰質數D1和D2(即D1-D2是最大的),如果存在相同距離的其他相鄰質數對,則輸出第一對。輸入格式 每行輸入兩個整數L和U,其中L和U的差值不會超過1000000。輸出格式 對于每個L和U ,輸出一個結果,結果占一行。結果包括距離最近的相鄰質數對和距離最遠的相鄰質數對。(具體格式參照樣例)如果L和U之間不存在質數對,則輸出“There are no adjacent primes.”。數據范圍 1≤L<U≤231?1 輸入樣例: 2 17 14 17 輸出樣例: 2,3 are closest, 7,11 are most distant. There are no adjacent primes.

1-R的質數全求是不可能的,

只需要L-R之間的且很小,所以,求到根號R就行,把L-R之間的合數標出來

https://www.acwing.com/solution/content/11586/

#include<cstdio> #include<iostream> #include<cstring> #include<cmath> using namespace std; const int MAXN=1000001,INF=2147483647; int primes[MAXN]; bool notPrime[MAXN]; int primeCnt=0; void initPrime(){for(int i=2;i<=sqrt(INF);i++){if(notPrime[i])continue;primes[++primeCnt]=i;for(int j=2;j<=sqrt(INF)/i;j++){notPrime[i*j]=1;} } } int newPrimes[MAXN]; int main(){initPrime();int l,r;while(cin>>l>>r){memset(notPrime,0,sizeof(notPrime));if(l==1)notPrime[0]=1;//特判for(int i=1;i<=primeCnt;i++){for(int j=l/primes[i];j<=r/primes[i];j++){if(j>1)notPrime[primes[i]*j-l]=1;}}int newPrimeCnt=0;for(int i=l;i<=r;i++){if(!notPrime[i-l])newPrimes[++newPrimeCnt]=i;if(i==r)break;}int minDelta=INF,maxDelta=0;int minX1,minX2,maxX1,maxX2;for(int i=1;i<newPrimeCnt;i++){int nowDelta=newPrimes[i+1]-newPrimes[i];if(nowDelta<minDelta){minDelta=nowDelta;minX1=newPrimes[i],minX2=newPrimes[i+1];}if(nowDelta>maxDelta){maxDelta=nowDelta;maxX1=newPrimes[i],maxX2=newPrimes[i+1];}}if(minDelta==INF)printf("There are no adjacent primes.\n");//else printf("%d,%d are closest, %d,%d are most distant.\n",minX1,minX2,maxX1,maxX2);}return 0; }

///從sqrt(L)開始算是不行的

這個原理是一樣的,但是用的數組太大,應該改成兩個新的小數組a[0]代表L,a[1]代表L+1,就能過了

#include <iostream> #include<bits/stdc++.h> using namespace std; typedef long long ll; #define maxn 2000005 bool v[maxn];///1為質數 bool he[maxn];///0為合數 void prime(int n) {memset(v,0,sizeof(v));for(int i=2;i<=n;i++){if(v[i]){he[i]=0;continue;}for(int j=i;j<=n/i;j++){v[i*j]=1;}} }int main() { // ios::sync_with_stdio(0); // cin.tie(0); // cout.tie(0);memset(he,1,sizeof(he));prime(sqrt(maxn));///多組輸入,我就直接求一遍sqrt(maxn)得了int L,R;he[1]=0;while(cin>>L>>R){for(int i=2;i<=sqrt(R)+1;i++)///從sqrt(L)開始算是不行的{for(int j=2;j<=sqrt(R)+1;j++){he[i*j]=0;}}int lbuf,rbuf,lmax,rmax,lmin,rmin,maxbuf,minbuf;///這里的l和r我指的是結果int cnt=L;for(;cnt<=R;cnt++){///尋找第一個質數if(he[cnt]==1){break;}}if(cnt==R+1){cout<<"There are no adjacent primes."<<endl;continue;} // cout<<"mincnt"<<cnt<<endl;lbuf=rbuf=cnt;rbuf++;///最小值不能是同一個數啊minbuf=maxn;maxbuf=0;for(;rbuf<=R;rbuf++)///向右尋找質數{if(he[rbuf]!=0){///最大if(maxbuf<rbuf-lbuf){maxbuf=rbuf-lbuf;rmax=rbuf;lmax=lbuf;}if(minbuf>rbuf-lbuf){minbuf=rbuf-lbuf;rmin=rbuf;lmin=lbuf;}lbuf=rbuf;}}if(minbuf==maxn&&maxbuf==0)///最大最小值沒變過,用來濾掉只有一個質數和邊界相等{cout<<"There are no adjacent primes."<<endl;continue;}printf("%d,%d are closest, %d,%d are most distant.\n",lmin,rmin,lmax,rmax);}return 0; }

階乘分解

給定整數 N ,試把階乘 N! 分解質因數,按照算術基本定理的形式輸出分解結果中的 pi 和 ci 即可。輸入格式 一個整數N。輸出格式 N! 分解質因數后的結果,共若干行,每行一對pi,ci,表示含有pcii項。按照pi從小到大的順序輸出。數據范圍 1≤N≤106 輸入樣例: 5 輸出樣例: 2 3 3 1 5 1 樣例解釋 5!=120=23?3?5

這道題很快樂,唯一就是數很大,所以只判斷質因子

另外n的階乘的質因子不會超過n,所以就直接只計算相應的就可以啦

還有就是不能直接求出來階乘,必炸,從1~n每個數求就好(對于每個質因子)

但這樣還是要遍歷,所以要用離散數學的一個公式

#include<cstdio> #include<iostream> using namespace std; const int MAXN=1e6; int primes[MAXN],primeCnt=0; bool notPrime[2*MAXN]; void initPrime(int x){//打表for(int i=2;i<=x;i++){if(notPrime[i])continue;for(int j=2;j<=x/i;j++){notPrime[i*j]=1;}}for(int i=2;i<=x;i++)//把打好的表轉移if(!notPrime[i])primes[++primeCnt]=i; } int ans[MAXN],ansValue[MAXN]; int main(){int n;scanf("%d",&n);initPrime(n);for(int i=1;i<=primeCnt;i++){///對已知的質數看是不是因子int tmpN=n,nowPrime=primes[i],nowAns=0;while(tmpN){//上面的公式nowAns+=(tmpN/nowPrime);tmpN/=nowPrime;}printf("%d %d\n",nowPrime,nowAns);}return 0; }https://www.acwing.com/solution/content/4960/

0x32約數

定理三個推論

單個數正約數集合–試除法(從1除到根號n)

推論,約束個數上限為2倍根號n

1~n 每個數的正約數集合-----倍數法(乘出來誰給誰)(不要重復)

推論


反素數

對于任何正整數x,其約數的個數記作g(x),例如g(1)=1g(6)=4。如果某個正整數x滿足:對于任意的小于x的正整數 i,都有g(x)>g(i) ,則稱x為反素數。例如,整數1246等都是反素數。現在給定一個數N,請求出不超過N的最大的反素數。輸入格式 一個正整數N。輸出格式 一個整數,表示不超過N的最大反素數。數據范圍 1≤N≤2?109 輸入樣例: 1000 輸出樣例: 840

這道題是數學推導出約束,解法是深搜


#include <iostream> #include<bits/stdc++.h> using namespace std; typedef long long ll; int ps[]={2,3,5,7,11,13,17,19,23,29}; int sum=0,minx; int n; void dfs(int u,int last,ll p,int s) //當前是第幾個因子, //上一個質數的次數 //上一個之后的乘積 //當前約數個數 {if(s>sum||s==sum&&p<minx)///更新,要么最大,要么相同并更小{sum=s;minx=p;}for(int i=1;i<=last;i++)///暴搜各因子次數///到last是遞減{if((ll)p*ps[u]>n)break;///dp*=ps[u];dfs(u+1,i,p,s*(i+1));///s*(i+1)是因子個數公式}}int main() {cin>>n;dfs(0,30,1,1);///從第0個起,上一個質數的次數,當前乘積為1cout<<minx<<endl;return 0; }

余數之和

給出正整數n和k,計算j(n, k)=k mod 1 + k mod 2 + k mod 3 ++ k mod n的值。例如j(5, 3)=3 mod 1 + 3 mod 2 + 3 mod 3 + 3 mod 4 + 3 mod 5=0+1+0+3+3=7。輸入格式 輸入僅一行,包含兩個整數n, k。輸出格式 輸出僅一行,即j(n, k)。數據范圍 1≤n,k≤109 輸入樣例: 5 3 輸出樣例: 7

這個題算法短到離譜,推導難到離譜,直接看大佬的吧

https://www.acwing.com/solution/content/6702/

#include <cstdio> #include <iostream> using namespace std; typedef long long LL; int n, k, l, r; LL ans; int main() {scanf("%d%d", &n, &k);ans = (LL)n * k;for (l = 1; l <= n; l = r + 1) {///l每次都直接跳成r+1,另外如果r+1了還正好breakif(k / l == 0) break;r = min(k / (k / l), n);///求上界ans -= (LL)(k / l) * (l + r) * (r - l + 1) / 2;///下界到上屆之間求等差數列}printf("%lld\n", ans);return 0; }

最大公約和最小公倍一些定理


hankson的趣味題

法一:


搜索算法:深搜

#include <iostream> #include <algorithm> #include <vector>using namespace std;typedef long long LL; typedef pair<int, int> PII;const int N = 45000, M = 50;int primes[N], cnt; bool st[N];PII factor[M]; int cntf;int divider[N], cntd;void get_primes(int n) {for (int i = 2; i <= n; i ++ ){if (!st[i]) primes[cnt ++ ] = i;for (int j = 0; primes[j] <= n / i; j ++ ){st[primes[j] * i] = true;if (i % primes[j] == 0) break;}} }int gcd(int a, int b) {return b ? gcd(b, a % b) : a; }void dfs(int u, int p)///p是當前這個次數組合的結果 {if (u > cntf)///cntf是質因子種類和{divider[cntd ++ ] = p;return;}for (int i = 0; i <= factor[u].second; i ++ )///本因子可以選0~factor.second個{dfs(u + 1, p);p *= factor[u].first;} }int main() {get_primes(N);///處理出質數int n;scanf("%d", &n);while (n -- ){int a0, a1, b0, b1;scanf("%d%d%d%d", &a0, &a1, &b0, &b1);int d = b1;cntf = 0;for (int i = 0; primes[i] <= d / primes[i]; i ++ )///處理出d的因子序列(每個因子多少次){int p = primes[i];if (d % p == 0){int s = 0;while (d % p == 0) s ++, d /= p;factor[ ++ cntf] = {p, s};}}if (d > 1) factor[ ++ cntf] = {d, 1};///如果不是1的話再加上自身(也可以寫到上面特判)cntd = 0;dfs(1, 1);///搜索出d的所有因子int res = 0;for (int i = 0; i < cntd; i ++ ){int x = divider[i];if (gcd(x, a0) == a1 && (LL)x * b0 / gcd(x, b0) == b1)///對每個因子進行判斷{res ++ ;}}printf("%d\n", res);}return 0; }

互質與歐拉函數

性質



可見的點

在一個平面直角坐標系的第一象限內,如果一個點(x,y)與原點(0,0)的連線中沒有通過其他任何點,則稱該點在原點處是可見的。例如,點(4,2)就是不可見的,因為它與原點的連線會通過點(2,1)。部分可見點與原點的連線如下圖所示:3090_1.png編寫一個程序,計算給定整數N的情況下,滿足0≤x,y≤N的可見點(x,y)的數量(可見點不包括原點)。輸入格式 第一行包含整數C,表示共有C組測試數據。每組測試數據占一行,包含一個整數N。輸出格式 每組測試數據的輸出占據一行。應包括:測試數據的編號(從1開始),該組測試數據對應的N以及可見點的數量。同行數據之間用空格隔開。數據范圍 1≤N,C≤1000 輸入樣例: 4 2 4 5 231 輸出樣例: 1 2 5 2 4 13 3 5 21 4 231 32549

這里的歐拉函數是類似素數篩的(簡單解法)

#include <iostream> #include<bits/stdc++.h> using namespace std; typedef long long ll; #define maxn 1005 ll p[maxn]; void euler(int n) {for(int i=2;i<=n;i++){p[i]=i;}for(int i=2;i<=n;i++){if(p[i]==i){for(int j=i;j<=n;j+=i)///i的倍數{p[j]=p[j]*(i-1)/i;}}} } int main() {euler(maxn-3);int n,c;cin>>c;int buf=c;while(c--){cin>>n;if(n==0){cout<<0<<endl;///特判continue;}int ans2=0;int ans=3;for(int i=2;i<=n;i++){ans2+=p[i];}ans+=2*ans2;cout<<buf-c<<" "<<n<<" "<<ans<<endl;}return 0; } 與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的蓝桥备赛第三周 倍增+贪心+素数+约数的全部內容,希望文章能夠幫你解決所遇到的問題。

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