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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[选拔赛1]花园(矩阵快速幂),JM的月亮神树(最短路),保护出题人(斜率优化)

發(fā)布時(shí)間:2023/12/3 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [选拔赛1]花园(矩阵快速幂),JM的月亮神树(最短路),保护出题人(斜率优化) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

多年不考試,一夜回到解放前

  • T1:花園
    • title
    • solution
    • code
  • T2:月亮神樹
    • title
    • solution
    • code
  • T3:保護(hù)出題人
    • title
    • solution
    • code

T1:花園

title

小 L 有一座環(huán)形花園,沿花園的順時(shí)針方向,他把各個(gè)花圃編號(hào)為 1~n。花圃 1 和 n 是相鄰的。
他的環(huán)形花園每天都會(huì)換一個(gè)新花樣,但他的花園都不外乎一個(gè)規(guī)則:任意相鄰 m 個(gè)花圃中都只有不超過 k 個(gè) C 形的花圃,其余花圃均為 P 形的花圃。
例如,若 n=10 , m=5 , k=3 ,則
CCPCPPPPCC 是一種不符合規(guī)則的花圃。
CCPPPPCPCP 是一種符合規(guī)則的花圃。
請(qǐng)幫小 L 求出符合規(guī)則的花園種數(shù)對(duì) 109+7 取模的結(jié)果。
【輸入格式】
只有一行三個(gè)整數(shù),分別表示 n, m, k。
【輸出格式】
輸出一行一個(gè)整數(shù)表示答案。
【樣例1】
garden.in garden.out
10 5 3 458
【樣例2】
garden.in garden.out
6 2 1 18
【數(shù)據(jù)規(guī)模與約定】
對(duì)于 40% 的數(shù)據(jù),保證 n≤20。
對(duì)于 80% 的數(shù)據(jù),保證 n≤105。
對(duì)于 100% 的數(shù)據(jù),保證 2≤n≤1015 ,2≤m≤min(n,5),1≤k≤m。

solution

不得不說一句,這個(gè)出題人是很有良心的


首先40分,直接暴力枚舉出每一種花圃裝修,然后進(jìn)行checkcheckcheck


接著80分,看數(shù)據(jù)范圍就可以明顯被n,mn,mn,m的量級(jí)差給沖擊到,mmm極其小,花圃不是CCC就是PPP
順其自然的聯(lián)想到狀壓dpdpdp求解,設(shè)dp[i][s]dp[i][s]dp[i][s]表示到第iii個(gè)花圃為止,最后連續(xù)的mmm個(gè)花圃狀態(tài)為sss
dp[i][s]=∑s=0(1<<m)?1dp[i?1][s]dp[i][s]=\sum_{s=0}^{(1<<m)-1}dp[i-1][s]dp[i][s]=s=0(1<<m)?1?dp[i?1][s]
當(dāng)然這中間的轉(zhuǎn)移需要判斷一下sss中是否111過多(假設(shè)CCC為1)
兩者是否有轉(zhuǎn)移關(guān)聯(lián)性,因?yàn)閷?duì)于iii而言的前m?1m-1m?1個(gè)花圃應(yīng)該是與i?1i-1i?1的后m?1m-1m?1個(gè)花圃是一樣的


最后100分
顯而易見,我們需要消除掉nnn帶來的巨大不可承受的時(shí)間復(fù)雜度,一般來說這么大的nnn
要么發(fā)現(xiàn)實(shí)現(xiàn)根本與nnn不掛鉤(通過某些轉(zhuǎn)移方程式),要么壓縮成logloglog,亦或各種優(yōu)化
在80分狀壓的時(shí)候,我畫了個(gè)示意圖,要求轉(zhuǎn)移之間某些花圃必須一一對(duì)應(yīng),連線段之間的相同
讓我的靈感一瞬閃過——矩陣快速冪!!!

只要兩個(gè)之間可以轉(zhuǎn)移我就置為111,最后把對(duì)角線的值加起來即可

code

#include <cstdio> #include <cstring> using namespace std; #define mod 1000000007 #define ll long long ll n, ans; int m, k, cnt; int t[205];bool count( int S ) {int tot = 0;while( S ) tot += S & 1, S >>= 1;return tot > k; }bool comp( int s1, int s2 ) {for( int i = 0;i <= m - 2;i ++ ) {int x1 = ( s1 >> i ) & 1;int x2 = ( s2 >> ( i + 1 ) ) & 1;if( x1 != x2 ) return 1;}return 0; } struct Matrix {ll c[50][50];Matrix() {memset( c, 0, sizeof( c ) );}Matrix operator * ( const Matrix &p ) {Matrix res;for( int i = 1;i <= cnt;i ++ )for( int k = 1;k <= cnt;k ++ )for( int j = 1;j <= cnt;j ++ )res.c[i][j] = ( res.c[i][j] + c[i][k] * p.c[k][j] % mod ) % mod;return res;}}A, B;Matrix qkpow( Matrix x, ll y ) {Matrix res;for( int i = 1;i <= cnt;i ++ ) res.c[i][i] = 1;while( y ) {if( y & 1 ) res = res * x;x = x * x;y >>= 1;}return res; }int main() {scanf( "%lld %d %d", &n, &m, &k );int S = 1 << m;for( int i = 0;i < S;i ++ )if( count( i ) ) continue;else t[++ cnt] = i;for( int i = 1;i <= cnt;i ++ )for( int j = 1;j <= cnt;j ++ )if( comp( t[i], t[j] ) ) continue;else A.c[i][j] = 1;B = qkpow( A, n );for( int i = 1;i <= cnt;i ++ )ans = ( ans + B.c[i][i] ) % mod;printf( "%lld", ans );return 0; }

T2:月亮神樹

title

JM今天過得實(shí)在是太慘了,他肥腸不爽,因此他搬出了他祖?zhèn)鞯脑铝辽駱洹T铝辽駱涞墓廨x照耀XJTUACM,每分鐘都可以從所有被照射的人的手中奪取他1%的財(cái)產(chǎn)。JM覺得他很快就能賺得盆滿缽滿。然而月亮神樹不久后突然失控了,不僅不把它奪來的財(cái)產(chǎn)交給JM,甚至開始奪取JM的財(cái)產(chǎn),把JM氣瘋了,趕緊關(guān)閉了月亮神樹。
因?yàn)樵铝辽駱錄]運(yùn)行多久就被關(guān)掉了,所以大家并沒有損失多少,迫于月亮神樹的威壓,并沒有人去理它。可是wzk昨天剛中了彩票,賺了100000000000¥,轉(zhuǎn)眼就被剝奪了很多。因?yàn)閣zk太rich了,所以他的損失格外大。為了奪回財(cái)產(chǎn),無敵的wzk決定消滅月亮神樹。
月亮神樹的構(gòu)造非常神奇,它的枝杈交錯(cuò)縱橫,樹上甚至存在環(huán)路,可以視為一個(gè)無向帶權(quán)連通圖的結(jié)構(gòu)。月亮神樹有一個(gè)核心節(jié)點(diǎn),記為 s 。要想消滅月亮神樹,必須找到月亮神樹的嚴(yán)格最不科學(xué)生成樹,這是它的弱點(diǎn),這樣就能將其一舉摧毀。
定義:一個(gè)圖 G 的不科學(xué)生成樹是 G 的一棵子樹,在這棵子樹上,從核心節(jié)點(diǎn) s 到任意一個(gè)節(jié)點(diǎn) u 的最短路徑長度,和在原圖上是等長的。其中節(jié)點(diǎn) s 是月亮神樹的核心節(jié)點(diǎn)。
定義:一個(gè)圖 G 的最不科學(xué)生成樹是 G 的所有不科學(xué)生成樹中,邊權(quán)和最小的一棵樹。
定義:一個(gè)圖 G 的嚴(yán)格最不科學(xué)生成樹是 G 的所有最不科學(xué)生成樹中,有序邊序列的字典序最小的一棵樹。
定義:一個(gè)圖 G 的有序邊序列是指,將圖上所有邊按編號(hào)從小到大排序后得到的編號(hào)序列。當(dāng)然,子圖子樹也適用。
現(xiàn)在給定月亮神樹,即給定一個(gè) n 個(gè)點(diǎn) m 條邊的無向帶權(quán)連通圖,點(diǎn)的編號(hào)從1到n,邊的編號(hào)從1到m,給定核心節(jié)點(diǎn)的編號(hào) s ,求其嚴(yán)格最不科學(xué)生成樹。
?
【輸入格式】
第一行三個(gè)正整數(shù) n,m,s 。
接下來 m 行,第 i 行三個(gè)正整數(shù) u,v,w ,表示編號(hào)為 i 的邊。
輸入保證圖是連通的,保證圖上不含重邊和自環(huán)。。
【輸出格式】
第一行兩個(gè)正整數(shù) cnt 和 sum ,用空格隔開,其中 cnt 表示嚴(yán)格最不科學(xué)生成樹的邊的個(gè)數(shù), sum 表示嚴(yán)格最不科學(xué)生成樹的邊權(quán)和。
接下來一行 cnt 個(gè)正整數(shù),用空格隔開,為樹上所有邊的編號(hào),按編號(hào)從小到大輸出。
【樣例1】
moontree.in moontree.out
3 3 3
1 2 1
2 3 1
1 3 2 2 2
1 2
【樣例2】
moontree.in moontree.out
4 4 4
2 3 1
1 2 1
3 4 1
4 1 2 3 4
1 3 4
【數(shù)據(jù)規(guī)模與約定】
對(duì)于25%的數(shù)據(jù), 1≤n,m≤10 。
另有25%的數(shù)據(jù), 1≤n,m≤100 。
對(duì)于100%的數(shù)據(jù), 1≤n,m≤3*105 ,1≤wi≤109 。

solution

老師說這道題最水,可我這道題的分最少

聽完題解后覺得——確實(shí)很水
堆優(yōu)化dijkstradijkstradijkstra時(shí)間復(fù)雜度O(nlogn)O(nlogn)O(nlogn)凸(艸皿艸 )!!!考試時(shí)我就想著先求出最短路,但我想著dijkstradijkstradijkstra時(shí)間復(fù)雜度不是O(n2)O(n^2)O(n2)嘜,我連堆優(yōu)化寫法都想好了!!但是我敗在了時(shí)間復(fù)雜度上面,我就沒敲,靠!!一直寫的這種,我竟不知是堆優(yōu)化,鴨血!!!


首先跑出每個(gè)點(diǎn)距離超級(jí)源點(diǎn)的最短路,然后思考對(duì)于每個(gè)點(diǎn)可能存在不止一條最短路
此時(shí)就要保證權(quán)值最小,權(quán)值最小的保證下又要編號(hào)最小
所以當(dāng)同時(shí)多條最短路出現(xiàn)時(shí),取權(quán)值最小,更新編號(hào)數(shù)組
權(quán)值一樣時(shí),選編號(hào)更小者即可


code

#include <queue> #include <cstdio> #include <vector> #include <cstring> #include <algorithm> using namespace std; #define ll long long #define MAXN 300005 struct Gragh {int v, id;ll w;Gragh(){}Gragh( int V, ll W, int ID ) {v = V, w = W, id = ID;} }; struct node {int v;ll w;node(){}node( int V, ll W ) {v = V, w = W;}bool operator < ( const node &t ) const {return w > t.w;} }; struct edge {int u, v, id;ll w;edge(){}edge( int U, int V, ll W, int ID ) {u = U, v = V, w = W, id = ID;} }E[MAXN]; priority_queue < node > q; vector < Gragh > G[MAXN]; int n, m, s, tot, cnt; ll ans; int flag[MAXN]; ll dis[MAXN]; bool vis[MAXN], used[MAXN];void dijkstra() {memset( dis, 0x3f, sizeof( dis ) );dis[s] = 0;q.push( node( s, 0 ) );while( ! q.empty() ) {int u = q.top().v; q.pop();if( vis[u] ) continue;vis[u] = 1;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i].v, w = G[u][i].w, id = G[u][i].id;if( dis[v] > dis[u] + w ) {dis[v] = dis[u] + w;q.push( node( v, dis[v] ) );flag[v] = id;}else if( dis[v] == dis[u] + w ) {if( w < E[flag[v]].w ) flag[v] = id;else if( w == E[flag[v]].w && id < E[flag[v]].id )flag[v] = id;}}} }int main() {scanf( "%d %d %d", &n, &m, &s );for( int i = 1;i <= m;i ++ ) {int u, v; ll w;scanf( "%d %d %lld", &u, &v, &w );G[u].push_back( Gragh( v, w, i ) );G[v].push_back( Gragh( u, w, i ) );E[i] = edge( u, v, w, i );}dijkstra();for( int i = 1;i <= n;i ++ )if( flag[i] ) {++ tot, ans += E[flag[i]].w;used[flag[i]] = 1;}printf( "%d %lld\n", tot, ans );for( int i = 1;i <= m;i ++ )if( used[i] ) printf( "%d ", i );return 0; }

T3:保護(hù)出題人

title

出題人銘銘認(rèn)為給 SDOI2012 出題太可怕了,因?yàn)榭傄涣R,于是他又給 SDOI2013 出題了。
參加 SDOI2012 的小朋友們釋放出大量的僵尸,企圖攻擊銘銘的家。而你作為 SDOI2013的參賽者,你需要保護(hù)出題人銘銘。
僵尸從唯一一條筆直道路接近,你們需要在銘銘的房門前放置植物攻擊僵尸,避免僵尸碰到房子。第一關(guān),一只血量為 a1 點(diǎn)的僵尸從距離房子 x1 米處勻速接近,你們放置了攻擊力為 y1點(diǎn)/秒的植物進(jìn)行防御;第二關(guān),在上一關(guān)基礎(chǔ)上,僵尸隊(duì)列排頭增加一只血量為 a2 點(diǎn)的僵尸,與后一只僵尸距離 d 米,從距離房子 x2 米處勻速接近,你們重新放置攻擊力為y2 點(diǎn)/秒的植物;……;第 n 關(guān),僵尸隊(duì)列共有 n 只僵尸,相鄰兩只僵尸距離 d 米,排頭僵尸血量為 an 點(diǎn),排第二的僵尸血量 an-1 ,以此類推,排頭僵尸從距離房子 xn 米處勻速接近,其余僵尸跟隨排頭同時(shí)接近,你們重新放置攻擊力為 yn 點(diǎn)/秒的植物。
每只僵尸直線移動(dòng)速度均為 1 米/秒,由于植物射擊速度遠(yuǎn)大于僵尸移動(dòng)速度,可忽略植物子彈在空中的時(shí)間。所有僵尸同時(shí)出現(xiàn)并接近,因此當(dāng)一只僵尸死亡后,下一只僵尸立刻開始受到植物子彈的傷害。
游戲得分取決于你們放置的植物攻擊力的總和,和越小分?jǐn)?shù)越高,為了追求分?jǐn)?shù)上界,你們每關(guān)都要放置攻擊力盡量小的植物。
作為 SDOI2013 的參賽選手,你們能保護(hù)出題人么?
【輸入格式】
第一行兩個(gè)空格隔開的正整數(shù) n 和 d,分別表示關(guān)數(shù)和相鄰僵尸間的距離。
接下來 n 行每行兩個(gè)空格隔開的正整數(shù),第 i + 1 行為 ai和 xi,分別表示相比上一關(guān)在僵尸隊(duì)列排頭增加血量為 ai 點(diǎn)的僵尸,排頭僵尸從距離房子 xi 米處開始接近。
【輸出格式】
一個(gè)數(shù),n 關(guān)植物攻擊力的最小總和 ,保留到整數(shù)。
?
【樣例1】
protect.in protect.out
5 2
3 3
1 1
10 8
4 8
2 3 7

【樣例1 說明】
第一關(guān):距離房子 3 米處有一只血量 3 點(diǎn)的僵尸,植物最小攻擊力為 1.00000;
第二關(guān):距離房子 1 米處有一只血量 1 點(diǎn)的僵尸、3 米處有血量 3 點(diǎn)的僵尸,植物最小攻擊力為 1.33333;
第三關(guān):距離房子 8 米處有一只血量 10 點(diǎn)的僵尸、10 米處有血量 1 點(diǎn)的僵尸、12 米處有血量 3 點(diǎn)的僵尸,植物最小攻擊力為 1.25000;
第四關(guān):距離房子 8 米處有一只血量 4 點(diǎn)的僵尸、10 米處有血量 10 點(diǎn)的僵尸、12 米處有血量 1 點(diǎn)的僵尸、14 米處有血量 3 點(diǎn)的僵尸,植物最小攻擊力為 1.40000;
第五關(guān):距離房子 3 米處有一只血量 2 點(diǎn)的僵尸、5 米處有血量 4 點(diǎn)的僵尸、7 米處有血量 10 點(diǎn)的僵尸、9 米處有血量 1 點(diǎn)的僵尸、11 米處有血量 3 點(diǎn)的僵尸,植物最小攻擊力為 2.28571。
【數(shù)據(jù)規(guī)模與約定】
對(duì)于 30%的數(shù)據(jù),n≤103 。
對(duì)于 50%的數(shù)據(jù),n≤104 。
對(duì)于 70%的數(shù)據(jù),1≤n≤105 ,1≤d≤106 ,1≤x≤106 ,1≤a≤106 。
對(duì)于 100%的數(shù)據(jù), 1≤n≤105 ,1≤d≤1012 ,1≤x≤1012 ,1≤a≤1012 。

solution

此題的x,ax,ax,a我們可以抽象在二維平面上,就很想我們做的三分燈泡模型↓↓
設(shè)dp[i][j]dp[i][j]dp[i][j]表示消滅第iii關(guān)卡前i?ji-ji?j個(gè)僵尸所需要的攻擊力
為了保證自己不被吃掉,我們就要求第iii關(guān)卡的maxdp[i][j]max{dp[i][j]}maxdp[i][j]
對(duì)于jjj而言,攻擊力要求為(ai+ai?1+...+aj)/(xi+d?(i?j))(a_i+a_{i-1}+...+a_j)/(x_i+d*(i-j))(ai?+ai?1?+...+aj?)/(xi?+d?(i?j))
對(duì)于另一個(gè)kkk而言,假設(shè)j<kj<kj<k,則攻擊力要求為
(ai+ai?1+...aj+...ak)/(xi+d?(i?j+j?k))(a_i+a_{i-1}+...a_j+...a_k)/(x_i+d*(i-j+j-k))(ai?+ai?1?+...aj?+...ak?)/(xi?+d?(i?j+j?k))
A=ai+ai?1+...+aj,B=xi+d?(i?j)A=a_i+a_{i-1}+...+a_j,B=x_i+d*(i-j)A=ai?+ai?1?+...+aj?,B=xi?+d?(i?j)
則兩個(gè)式子分別為
A/B,(A+aj?1+...+ak)/(B+d?(j?k))A/B,(A+a_{j-1}+...+a_k)/(B+d*(j-k))A/B,(A+aj?1?+...+ak?)/(B+d?(j?k))
交叉相成
A?B+A?d?(j?k),A?B+B?(aj?1+...+ak)A*B+A*d*(j-k),A*B+B*(a_{j-1}+...+a_k)A?B+A?d?(j?k),A?B+B?(aj?1?+...+ak?)
相抵消
A?d?(j?k),B?(aj?1+...ak)A*d*(j-k),B*(a_{j-1}+...a_k)A?d?(j?k),B?(aj?1?+...ak?)
在轉(zhuǎn)化
A/B,(aj?1+...+ak)/(d?(j?k))A/B,(a_{j-1}+...+a_k)/(d*(j-k))A/B,(aj?1?+...+ak?)/(d?(j?k))
最后推出我們想要的方程式
yi?=(1≤j≤i)max?{(sumi??sumj?1?)/(xi?+d×(i?j)}y_i?=(1≤j≤i)\ \ max?\{(sum_i??sum_{j?1}?)/(x_i?+d×(i?j)\}yi??=(1ji)??max?{(sumi???sumj?1??)/(xi??+d×(i?j)}
類似于斜率優(yōu)化一樣去維護(hù)一個(gè)下凸包,然后三分找最大斜率即可

code

#include <cstdio> #include <iostream> using namespace std; #define MAXN 100005 int n, top; double ans; long long d; int st[MAXN]; long long x[MAXN], a[MAXN], sum[MAXN];double calc1( int i, int j ) {return 1.0 * ( sum[i - 1] - sum[j - 1] ) / ( d * ( i - j ) ); }double calc2( int i, int j ) {return 1.0 * ( sum[i] - sum[j - 1] ) / ( x[i] + d * ( i - j ) ); }int main() {scanf( "%d %lld", &n, &d );for( int i = 1;i <= n;i ++ ) {scanf( "%lld %lld", &a[i], &x[i] );sum[i] = sum[i - 1] + a[i];}for( int i = 1;i <= n;i ++ ) {while( top > 1 && calc1( i, st[top] ) < calc1( st[top], st[top - 1] ) )top --;st[++ top] = i;int l = 1, r = top;while( l <= r ) {int tmp = ( r - l + 1 ) / 3;int mid1 = l + tmp - 1, mid2 = l + ( tmp << 1 ) - 1;if( mid1 == mid2 ) break;if( calc2( i, st[mid1] ) < calc2( i, st[mid2] ) ) l = mid1 + 1;else r = mid2 - 1;}ans += max( calc2( i, st[l] ), calc2( i, st[r] ) );}printf( "%0.f", ans );return 0; }

總結(jié)

以上是生活随笔為你收集整理的[选拔赛1]花园(矩阵快速幂),JM的月亮神树(最短路),保护出题人(斜率优化)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。