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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

等比数列三角形 (数论 + 黄金分割点)+ JOISC 2016 Day3 T3 「电报」(基环树 + 拓扑排序)

發布時間:2023/12/3 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 等比数列三角形 (数论 + 黄金分割点)+ JOISC 2016 Day3 T3 「电报」(基环树 + 拓扑排序) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • T1:等比數列三角形
    • 題目
    • 題解
    • 代碼實現
  • T2:電報
    • 題目
    • 題解
    • 代碼實現

T1:等比數列三角形

題目

求三邊都是 ≤n 的整數,且成等比數列的三角形個數
注意三角形面積不能為 0
注意 oeis 中未收錄此數列,所以并不需要去搜了

輸入格式
一行一個整數 n
輸出格式
一行一個整數表示答案

樣例
樣例輸入1
9
樣例輸出1
10
樣例解釋1
除去 9 個等邊三角形,還有 {4,6,9} 。

樣例輸入2
100
樣例輸出2
133

數據范圍與提示
一共有 4 個子任務,對于每一個子任務,你只有通過了該子任務的所有測試點,才能獲得此子任務的分數
有 10pts,保證 n≤10
有 20pts,保證 n≤105
有 20pts,保證 n≤105
有 50pts,保證 n≤1012
對于所有數據,有1≤ n≤1012

題解


注意{4,6,9},{6,4,9},{9,6,4}算同一個三角形,所以不用管順序
設三條邊從小到大分別為a,ak,ak2a,ak,ak^2a,ak,ak2(kkk為公比且為正整數)
所以1≤k1≤k1k


就然要構成三角形,必然要滿足
a+ak>ak2=>1+k>k2=>k2?k?1<0a+ak>ak^2=>1+k>k^2=>k^2-k-1<0a+ak>ak2=>1+k>k2=>k2?k?1<0
解得k<√5+12k<\frac{√5+1}{2}k<25+1?

綜上k∈[1,√5+12)k∈[1,\frac{√5+1}{2})k[1,25+1?)


接下來令k=pqk=\frac{p}{q}k=qp?(q,pq,pq,p互質),最大邊就表示為a?p2q2a*\frac{p^2}{q^2}a?q2p2?
最大邊≤n≤nn,故此q≤√nq≤√nqn
因為q=pkq=\frac{p}{k}q=kp?,那么

  • kkk取最大時,qqq取最小,把k=√5+12k=\frac{√5+1}{2}k=25+1?帶入就解出了qqq的最小值,
    但因為k取不到這個開區間,q的這個最小值也是一個開區間
  • 當k取最小時,qqq取最大,這是滿足q=pq=pq=pqqq的這個最大值是一個閉區間

綜上q∈(p?2√5+1,p]q∈(p*\frac{2}{√5+1},p]q(p?5+12?,p],在這里有個轉化思想,把ppp代換成qqq,得到q∈(q?2√5+1,q]q∈(q*\frac{2}{√5+1},q]q(q?5+12?,q]
我們就可以枚舉p∈[1,√n]p∈[1,√n]p[1,n],算出此時q的可取值個數
注意:其實理解成枚舉qqq也是說得通的


當這樣統計完后,會出現一個問題
{2,3,6},{4,6,9}\{2,3,6\},\{4,6,9\}{236},{469}這種公比為32\frac{3}{2}23?的三角形,會被重復計算進公比為64\frac{6}{4}46?
所以我們需要把這些排除掉,這也是為什么上面推導的時候pq\frac{p}{q}qp?要保證互質
這里就可以用類似埃篩的方法,把xxx的因數里面算過的三角形減掉

要正著減,如果倒著,公比為128\frac{12}{8}812?會先減掉公比為96\frac{9}{6}69?而這里面還包含著32\frac{3}{2}23?
會導致32\frac{3}{2}23?被重復減掉


代碼實現

#include <cstdio> #include <cmath> using namespace std; #define LL long long #define MAXN 1000005 LL n, result; int ok[MAXN]; int main() {scanf ( "%lld", &n );int sqt = sqrt ( n );for ( int i = 1;i <= sqt;i ++ ) {int t = i * ( 2 / ( sqrt ( 5 ) + 1 ) );ok[i] = i - t;}for ( LL i = 1;i <= sqt;i ++ )for ( LL j = i << 1;j <= sqt;j += i )ok[j] -= ok[i];for ( LL i = 1;i * i <= n;i ++ )result += ( n / ( i * i ) ) * ok[i];printf ( "%lld", result );return 0; }

T2:電報

題目

給出 n 個點,每個點的出度均為 1,給出這 n 個點初始指向的點A[i] ,和改變這個點指向的目標所需要的價值 C[i]。
求讓所有點強連通的最小花費。

輸入格式
第一行輸入一個數 n 表示點的個數。
之后的 n 行每行兩個數 A[i],C[i] 表示第 i 個點指向第 A[i] 個點,更改該點指向的點花費為 C[i]。
輸出格式
共一行,為讓所有點強連通的最小花費。

樣例
樣例輸入 1
4
2 2
1 4
1 3
3 1
樣例輸出 1
4
樣例解釋 1

很顯然,把 1–>2 的這條邊改成 (花費 4)的情況下構成強連通分量花費最小。

樣例輸入 2
4
2 2
1 6
1 3
3 1
樣例輸出 2
5
樣例解釋 2
很顯然把 1–>2 的這條邊改成 1–>4 花費 2,把 3–>1 的這條邊改成 3–>2 花費 3 的情況下構成強連通分量花費最小,總花費為 5。

樣例輸入 3
4
2 2
1 3
4 2
3 3
樣例輸出 3
4

樣例輸入 4
3
2 1
3 1
1 1
樣例輸出 4
0

題解


首先為了能變成強連通,樹上的點彼此之間需要破掉,先不動環上的點

如圖中:7,8,97,8,978910,11,12,1310,11,12,1310111213就必須破掉,破成一條鏈

要么把7→87\rightarrow878破掉,要么把7→97\rightarrow979破掉,然后讓7?8?97-8-97?8?9連成一條鏈

可以用拓撲排序找到不是環上的點,然后把這棵樹破成鏈,如果本身是鏈就不進行操作

圖就變成多個環和多棵樹的形態

顯然,環彼此之間是相互獨立的,就可以掃一次先處理出所有的環

我們在上面進行樹上破成鏈的時候,把環延伸的鏈或樹也一起破掉

如圖中:就把6→76\rightarrow7676→106\rightarrow10610都給破掉

接著如果變成強連通,環與環之間必須相互有路去連通

就是復活環與之外連的某一條邊

意味著我們要把環破掉一條邊和外界相連

那么這個時候,對于環上的最佳答案點肯定滿足把它與它父親在環上的邊破掉,然后把它與自己延伸的鏈的點進行相連的操作花費最小

破環就是自己的CCC值,與鏈上的點保留一條邊,就是找鏈上點的CCC的最大值

如圖中:我們要把6→16\rightarrow161破掉,復活6→76\rightarrow767或者6→106\rightarrow10610任意一條邊

而且必須復活至少一條,這樣才能讓環與外面進行連通

但是如果圖上有多個點的復活值是負數,那么肯定是全選上,使答案變得更小

在上面破 環與鏈的邊 的時候,我們就記錄最大值的CCC,復活的時候,肯定復活這一條邊,其他邊的消耗遠小于這一條邊破掉的消耗


最后我們來解釋一下代碼的一些地方,旁邊的小姐姐問了我很久

  • 為什么是建反圖:
    想一想,如果我們建正圖,每個點都只會有一個指向點,即每個點的vector里面都只有111個點,怎么破鏈,復活等以上的操作呢?
    換言之,每個點要知道自己的后繼,才能知道破哪些邊

  • flag||tot>1的問題,我們要知道
    當只有環的時候,如果環是多個,也需要破掉,使所有環彼此強連通
    當只有一個環的時候,如果環上有鏈也需要破掉,不然環上的點無法走到鏈上的點
    所以這里是取或,當且僅當原圖本身就是一個環才不用考慮復活


代碼實現

這里定義isCircle[i]
1:表示這個點不在環上(PS:可能誤導了許多親故 )
2:表示這個點在環上且已經經過了破樹或破鏈處理
0:表示這個點在環上但等待被處理

#include <queue> #include <cstdio> #include <vector> #include <cstring> #include <iostream> using namespace std; #define MAXN 100005 queue < int > q; vector < int > G[MAXN], circle[MAXN]; int n, tot; bool flag; int a[MAXN], c[MAXN]; int d[MAXN], g[MAXN], isCircle[MAXN]; long long result;int main() {scanf ( "%d", &n );for ( int i = 1;i <= n;i ++ ) {scanf ( "%d %d", &a[i], &c[i] );G[a[i]].push_back ( i );d[a[i]] ++;}for ( int i = 1;i <= n;i ++ )if ( ! d[i] ) {q.push ( i );isCircle[i] = 1;flag = 1;}while ( ! q.empty() ) {int t = q.front();q.pop();d[a[t]] --;if ( ! d[a[t]] ) {q.push ( a[t] );isCircle[a[t]] = 1;}}for ( int i = 1;i <= n;i ++ ) {if ( isCircle[i] == 1 ) {//破樹為鏈int Max = 0;for ( int j = 0;j < G[i].size();j ++ ) {Max = max ( Max, c[G[i][j]] );result += c[G[i][j]];}result -= Max;}else {for ( int j = 0;j < G[i].size();j ++ )if ( isCircle[G[i][j]] == 1 ) {//破環與外面延伸的鏈g[i] = max ( g[i], c[G[i][j]] );//記錄一條鏈的最大值result += c[G[i][j]];}if ( isCircle[i] == 0 )tot ++;int x = i;while ( isCircle[x] == 0 ) {//分離出環isCircle[x] = 2;circle[tot].push_back ( x );x = a[x];}}}if ( flag || tot > 1 ) {for ( int i = 1;i <= tot;i ++ ) {int Min = 0x3f3f3f3f;for ( int j = 0;j < circle[i].size();j ++ )//復活Min = min ( Min, c[circle[i][j]] - g[a[circle[i][j]]] );if ( Min >= 0 )//必須復活的一條邊result += Min;else {for ( int j = 0;j < circle[i].size();j ++ )if ( c[circle[i][j]] - g[a[circle[i][j]]] < 0 )//可多復活幾條邊result += c[circle[i][j]] - g[a[circle[i][j]]];//破掉i與fi的環上邊的時候,接的那一條邊肯定是接在fi上}}}printf ( "%lld", result );return 0; }

總結

以上是生活随笔為你收集整理的等比数列三角形 (数论 + 黄金分割点)+ JOISC 2016 Day3 T3 「电报」(基环树 + 拓扑排序)的全部內容,希望文章能夠幫你解決所遇到的問題。

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