日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

[2020-11-30 contest]数列(矩阵加速),秘密通道(dijkstra最短路)小X游世界树(换根dp),划分(数学)

發(fā)布時間:2023/12/3 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [2020-11-30 contest]数列(矩阵加速),秘密通道(dijkstra最短路)小X游世界树(换根dp),划分(数学) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 數(shù)列
    • solution
    • code
  • 秘密通道
    • solution
    • code
  • 小X游世界樹
    • solution
    • code
  • 劃分
    • solution
    • code

數(shù)列

a[1]=a[2]=a[3]=1 a[x]=a[x-3]+a[x-1] (x>3) 求 a 數(shù)列的第 n 項對 1000000007(10^9+7)取余的值。

輸入格式
第一行一個整數(shù) T,表示詢問個數(shù)。 以下 T 行,每行一個正整數(shù) n。

輸出格式
每行輸出一個非負整數(shù)表示答案。

樣例
輸入樣例
3
6
8
10
輸出樣例
4
9
19
數(shù)據(jù)范圍與提示
對于 30%的數(shù)據(jù) n<=100; 對于 60%的數(shù)據(jù) n<=2x107
對于 100%的數(shù)據(jù) T<=100,n<=2x109

solution

一眼題,沒得說

[a1,a2,a3]×[001100011]=[a2,a3,a4]\begin{bmatrix} a_1,a_2,a_3 \end{bmatrix}\times\begin{bmatrix} 0&0&1\\ 1&0&0\\ 0&1&1 \end{bmatrix}=\begin{bmatrix} a_2,a_3,a_4 \end{bmatrix}[a1?,a2?,a3??]×???010?001?101????=[a2?,a3?,a4??]

code

#include <cstdio> #include <cstring> #define mod 1000000007 #define ll long long struct Matrix {ll c[4][4];Matrix() {memset( c, 0, sizeof( c ) );}Matrix operator * ( const Matrix &p ) {Matrix ans;for( int i = 1;i <= 3;i ++ )for( int j = 1;j <= 3;j ++ )for( int k = 1;k <= 3;k ++ )ans.c[i][k] = ( ans.c[i][k] + c[i][j] * p.c[j][k] % mod ) % mod;return ans;}}base, v, result; int T, n;Matrix qkpow( Matrix x, int y ) {Matrix res;res.c[1][1] = res.c[2][2] = res.c[3][3] = 1;while( y ) {if( y & 1 ) res = res * x;x = x * x;y >>= 1;}return res; }int main() {freopen( "seq.in", "r", stdin );freopen( "seq.out", "w", stdout );base.c[1][1] = base.c[1][2] = base.c[1][3] = 1;v.c[1][3] = v.c[2][1] = v.c[3][2] = v.c[3][3] = 1;scanf( "%d", &T );while( T -- ) {scanf( "%d", &n );if( n <= 3 ) {printf( "1\n" );continue;}result = base * qkpow( v, n - 3 );printf( "%lld\n", result.c[1][3] );}return 0; }

秘密通道

有一副n×mn\times mn×m的地圖,有n×mn\times mn×m塊地,每塊是下列四種中的一種: 墻:用#表示,墻有 4 個面,分別是前面,后面,左面,右面。 起點:用 C 表示,為主角的起點,是一片空地。 終點:用 F 表示,為主角的目的地,是一片空地。 空地:用 . 表示。 其中除了墻不能穿過,其他地方都能走。 主角有以下 3 種操作:

移動到相鄰的前后左右的地方,花費一個單位時間。
向前后左右其中一個方向發(fā)射子彈,子彈沿直線穿過,打在最近的一堵墻的一面,然 后墻的這面就會形成一個開口通往秘密通道。同一時間最多只能有兩個開口,若出現(xiàn)有 3 個 開口,出現(xiàn)時間最早的開口會立即消失。該操作不用時間。
可以從一個與開口相鄰的空地跳進去,進入秘密通道,從另外一個開口正對的空地跳 出來。這個過程花費一個單位時間。 地圖四周都是墻,問主角最少用多少時間從 C 走到 F。C 和 F 只會出現(xiàn)一次。
輸入格式
第一行輸入兩個正整數(shù) n,m。 接下來 n 行,每行 m 個字符描述地圖。

輸出格式
輸出 1 個整數(shù),表示最短時間完成路途。如果無解輸出 nemoguce

樣例
輸入樣例1
4 4

#.F#
#C.#

輸出樣例1
2
輸入樣例2
6 8
########
#.##…F#
#C.##…#
#…#…#
#…##
########
輸出樣例2
4
數(shù)據(jù)范圍與提示
對于 50%的數(shù)據(jù),4 ≤ 𝑛, 𝑚 ≤ 15。 對于 100%的數(shù)據(jù),4 ≤ 𝑛, 𝑚 ≤ 500。

solution

兩眼題
這種走迷宮條件反射就想上bfs,不過很明顯?最短路
這道題還是很善良的,打槍是沒有時間的,當然就算有也一樣簡單
但是考場上,我想錯了,以為走到墻旁邊的格子再打槍一定是最優(yōu)的
然并卵👇

很明顯,我首先就得往下打一槍,再往右走,打槍穿墻瞬移
于是我被卡了30′

所以,對于地圖上的每一個點都有八條建邊可能
四個方向相鄰格子建邊邊權111
四個墻相鄰格子建邊均為四個方向上最近的墻的距離
n×mn\times mn×m個點,普通O(n2)dijkstraO(n^2)dijkstraO(n2)dijkstra整不動,就上堆優(yōu)化

code

#include <queue> #include <cstdio> #include <cstring> #include <iostream> using namespace std; #define maxn 505 struct node {int i, j, w;node(){}node( int I, int J, int W ) {i = I, j = J, w = W;}bool operator < ( const node &u ) const {return w > u.w;} }; priority_queue < node > q; int n, m; char s[maxn][maxn]; bool vis[maxn][maxn]; int Up[maxn][maxn], Down[maxn][maxn], Left[maxn][maxn], Right[maxn][maxn];bool inside( int x, int y ) {if( x < 1 || x > n || y < 1 || y > m ) return 0;else return 1; }void Push( int x, int y, int w ) {if( ! inside( x, y ) ) return;if( s[x][y] == '#' ) return;if( vis[x][y] ) return;q.push( node( x, y, w ) ); }void Dijkstra() {while( ! q.empty() ) {node u = q.top(); q.pop();int i = u.i, j = u.j, w = u.w;if( vis[i][j] ) continue;if( s[i][j] == 'F' ) {printf( "%d\n", w );return;}vis[i][j] = 1;Push( i - 1, j, w + 1 );Push( i + 1, j, w + 1 );Push( i, j - 1, w + 1 );Push( i, j + 1, w + 1 );int minn = min( min( i - Up[i][j], Down[i][j] - i ), min( j - Left[i][j], Right[i][j] - j ) );Push( Up[i][j] + 1, j, w + minn );Push( Down[i][j] - 1, j, w + minn );Push( i, Left[i][j] + 1, w + minn );Push( i, Right[i][j] - 1, w + minn );}printf( "nemoguce\n" ); }int main() {scanf( "%d %d", &n, &m );for( int i = 1;i <= n;i ++ ) {scanf( "%s", s[i] + 1 );for( int j = 1;j <= m;j ++ )if( s[i][j] == 'C' ) q.push( node( i, j, 0 ) );}for( int i = 1;i <= n;i ++ )for( int j = 1;j <= m;j ++ ) {if( s[i - 1][j] == '#' ) Up[i][j] = i - 1;else Up[i][j] = Up[i - 1][j];if( s[i][j - 1] == '#' ) Left[i][j] = j - 1;else Left[i][j] = Left[i][j - 1];}for( int i = n;i;i -- )for( int j = m;j;j -- ) {if( s[i + 1][j] == '#' ) Down[i][j] = i + 1;else Down[i][j] = Down[i + 1][j];if( s[i][j + 1] == '#' ) Right[i][j] = j + 1;else Right[i][j] = Right[i][j + 1];}Dijkstra();return 0; }

小X游世界樹

小 x 得到了一個(不可靠的)小道消息,傳說中的神島阿瓦隆在格陵蘭海的某處,據(jù)說那 里埋藏著亞瑟王的寶藏,這引起了小 x 的好奇,但當他想前往阿瓦隆時發(fā)現(xiàn)那里只有圣誕節(jié) 時才能到達,然而現(xiàn)在已經(jīng)春天了,不甘心的他將自己的目的地改成了世界樹,他耗費了大 量的時間,終于將自己傳送到了世界樹下。世界樹是一棵非常巨大的樹,它有著許許多多的 枝條以及節(jié)點,每個節(jié)點上都有一個平臺。好不容易來到傳說中的世界樹下,小 x 當然要爬 上去看看風景。小 x 每經(jīng)過一條邊都會耗費體力值。然而世界樹之主想給他弄(gáo)些 (d ǐan)麻(shì)煩(qíng),于是他在每條邊上都設了一個魔法陣,當小 x 踏上那條邊時會 被傳送回根節(jié)點,魔法陣只生效一次。這豈不是要累死小 x?幸運的是,每個平臺上都有無 數(shù)個加速器,這些加速器可以讓小 x 在當前節(jié)點所連的邊上耗費的體力值減少,不同平臺的 加速器性能不一定相同,但同一個平臺的加速器性能絕對相同。世界樹之主給了小 x 一次 “換根”的機會,他可以將世界樹的任何一個節(jié)點變?yōu)楦?#xff0c;但所有的邊都不能改變。小 x 想 問你,將根換為哪個節(jié)點能使小 x 爬到世界樹上的每個節(jié)點耗費的體力值和最少。默認編號 為 1 的點為初始根

輸入格式
第一行一個數(shù) n,表示有 n 個節(jié)點。 第二行 n 個數(shù) ai,表示每個平臺上的加速器的性能。 第三至 n+1 行,每行三個數(shù) bi,ci,di 分別表示這條無向邊的起點,終點與耗費的能量值。

輸出格式
第一行一個數(shù),表示要換成的節(jié)點,如果有多個點為根時耗費的體力值都最小,則輸出 編號最小的那個。如果保持為 1 是最優(yōu)的,就輸出 1。 第二行一個數(shù),表示最小耗費的體力值。

樣例
輸入樣例
4
2 1 3 3
1 2 3
1 3 4
2 4 6
輸出樣例
1
9
數(shù)據(jù)范圍與提示
如果以第一個點為根,則需要耗費 0(到 1)+1(到 2)+2(到 3)+6(到 4)=9 的能量值。 如果以第二個點為根,則需要耗費 2(到 1)+0(到 2)+4(到 3)+5(到 4)=11 的能量值。 如果以第三個點為根,則需要耗費 1(到 1)+2(到 2)+0(到 3)+7(到 4)=10 的能量值。 如果以第四個點為根,則需要耗費 5(到 1)+3(到 2)+7(到 3)+0(到 4)=15 的能量值。 很明顯以第一個點為根是最優(yōu)的。

對于 20%的數(shù)據(jù):n<=100 對于 40%的數(shù)據(jù):n<=1000 對于 60%的數(shù)據(jù):n<=8000 對于 80%的數(shù)據(jù):n<=100000 對于 100%的數(shù)據(jù):0<n<=700000;ai<=1000;1<=bi,ci<=n;di<=1000。

solution

一眼題,沒得跑,換根dp還是很裸的了
g[u]g[u]g[u]uuu子樹內(nèi)每個點到uuu所耗費的體力值之和
f[u]f[u]f[u]uuu子樹外所有點到uuu所耗費的體力值之和
很明顯👇
g[u]g[u]g[u]uuu兒子掛鉤,需要從下往上更新
f[u]f[u]f[u]uuu祖先掛鉤,需要從上往下更新
所以兩個分開用dfsdfsdfs?

然而我因為最后的極大值附小了,于是愉快地又爆掉了30′

code

#include <cstdio> #include <vector> using namespace std; #define maxn 700005 #define ll long long vector < pair < int, int > > G[maxn]; int n; int a[maxn], siz[maxn]; ll f[maxn], g[maxn], ans[maxn];void dfs1( int u, int fa ) {siz[u] = 1;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i].first, w = G[u][i].second;if( v == fa ) continue;dfs1( v, u );siz[u] += siz[v];g[u] += g[v] + 1ll * siz[v] * ( w - a[u] );} }void dfs2( int u, int fa ) {for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i].first, w = G[u][i].second;if( v == fa ) continue;f[v] = f[u] + g[u] - g[v] - 1ll * siz[v] * ( w - a[u] ) + 1ll * ( n - siz[v] ) * ( w - a[v] );ans[v] = g[v] + f[v];dfs2( v, u );} }int main() {scanf( "%d", &n );for( int i = 1;i <= n;i ++ )scanf( "%d", &a[i] );for( int i = 1, u, v, w;i < n;i ++ ) {scanf( "%d %d %d", &u, &v, &w );G[u].push_back( make_pair( v, w ) );G[v].push_back( make_pair( u, w ) );}dfs1( 1, 0 );dfs2( 1, 0 );ll result = 1ll << 60; int pos;ans[1] = g[1];for( int i = 1;i <= n;i ++ )if( ans[i] < result ) result = ans[i], pos = i;printf( "%d\n%lld", pos, result );return 0; }

劃分

有一個未知的序列 x,長度為 n。它的 K-劃分序列 y 指的是每連續(xù) K 個數(shù)的和得到劃 分序列,y[1]=x[1]+x[2]+…+x[K],y[2]=x[K+1]+x[K+2]+…+x[K+K]…。 若 n 不被 K 整除,則 y[n/K+1]可以由少于 K 個數(shù)加起來。 比如 n=13,K=5,則 y[1]=x[1]+…+x[5],y[2]=x[6]+…+x[10],y[3]=x[11]+x[12]+ x[13]。若小 A 只確定 x 的 K[1]劃分序列以及 K[2]劃分序列…K[M]劃分序列的值情況下, 問她可以確定 x 多少個元素的值。

輸入格式
第一行輸入兩個正整數(shù) n,M。 第二行輸入 M 個正整數(shù)表示 K[1],K[2]…K[M]。

輸出格式
輸出 1 個整數(shù),表示能確定的元素

樣例
輸入樣例1
3 1
2
輸出樣例1
1
輸入樣例2
6 2
2 3
輸出樣例2
2
數(shù)據(jù)范圍與提示
【樣例解釋】 【樣例 1 解釋】 小 A 知道 x 的 2-劃分序列,即分別知道 x[1]+x[2],x[3]的值。 小 A 可以知道 x[3]的值。 【樣例 2 解釋】 小 A 知道 x 的 2-劃分序列,即分別知道 x[1]+x[2],x[3]+x[4],x[5]+x[6] 的值。 小 A 知道 x 的 3-劃分序列,即分別知道 x[1]+x[2]+x[3] ,x[4]+x[5]+x[6] 的值。 小 A 可以知道 x[3],x[4]的值,個數(shù)為 2. 【數(shù)據(jù)范圍】 對于 20%的數(shù)據(jù),3 ≤ 𝑁 ≤ 2000, 𝑀 ≤ 3。 對于 40%的數(shù)據(jù),3 ≤ 𝑁 ≤ 5 ? 10^6。 對于 100%的數(shù)據(jù),3 ≤ 𝑁 ≤ 10^9, 1 ≤ 𝑀 ≤ 10,2 ≤ 𝐾[𝑖] < 𝑁。

solution

一眼題
一眼做不出來的題

首先很明顯可以發(fā)現(xiàn),若要確定xxx,當且僅當我們知道Sx,Sx?1S_x,S_{x-1}Sx?,Sx?1?
x=k1×a=k2×b+1=>k1×a?k2×b=1x=k_1\times a=k_2\times b+1\ =>\ k_1\times a-k_2\times b=1x=k1?×a=k2?×b+1?=>?k1?×a?k2?×b=1

發(fā)現(xiàn)這個式子長得很像擴展歐幾里得ax+by=1ax+by=1ax+by=1,當且僅當gcd(a,b)=1gcd(a,b)=1gcd(a,b)=1有解

求出最小正整數(shù)解a1,b1a_1,b_1a1?,b1?
則通解aaaa1+p×b1,p∈Za_1+ p\times b_1,p∈Za1?+p×b1?,pZ
去解一個不等式p×b1×ki+a1?b1≤np\times b_1\times k_i+a_1*b_1\le np×b1?×ki?+a1??b1?n

要是真這么簡單就歐兒啦
我們不僅可以很明顯的發(fā)現(xiàn)有解的條件是相差為111,也能很明顯地發(fā)現(xiàn)我們會算重
就算發(fā)現(xiàn)不了樣例也會告訴你血的教訓
容斥就好了,可我容斥不行啊!!

我們設s1s_1s1?表示所有aaa集合,s2s_2s2?表示所有bbb的方程。
這樣每一個kik_iki?只會存在于s1,s2s_1,s_2s1?,s2?或者都不存在。
這樣枚舉的復雜度是O(3m)O(3^m)O(3m)
容斥系數(shù)就是(?1)∣A∣+∣B∣(?1)^{|A|+|B|}(?1)A+B 推一推找找規(guī)律就知道了

這里涉及了同余方程的合并,就是他們的lcmlcmlcm

code

#include <cmath> #include <cstdio> #define int long long #define maxm 15 #define maxn 60000 int n, m, ans; int k[maxm], f[maxn];int gcd( int x, int y ) {if( ! y ) return x;else return gcd( y, x % y ); }int lcm( int x, int y ) {int d = gcd( x, y );return x / d * y; }int exgcd( int a, int b, int &x, int &y ) {if( ! b ) {x = 1, y = 0;return a;}else {int d = exgcd( b, a % b, y, x );y -= x * ( a / b );return d;} }int calc( int a, int b ) {int x, y;if( exgcd( a, b, x, y ) != 1 ) return 0;x = ( x % b + b ) % b;if( x * a > n ) return 0;else return ( n - x * a ) / ( a * b ) + 1; }void dfs( int s1, int s2, int x, int t1, int t2 ) {if( s1 > n || s2 > n ) return;if( x > m ) {if( ! t1 || ! t2 ) return;ans += ( ( t1 + t2 ) & 1 ? -1 : 1 ) * calc( s1, s2 );return;}dfs( lcm( s1, k[x] ), s2, x + 1, t1 + 1, t2 );dfs( s1, lcm( s2, k[x] ), x + 1, t1, t2 + 1 );dfs( s1, s2, x + 1, t1, t2 ); }signed main() {scanf( "%lld %lld", &n, &m );for( int i = 1;i <= m;i ++ )scanf( "%lld", &k[i] );k[++ m] = n;dfs( 1, 1, 1, 0, 0 );printf( "%lld", ans );return 0; }

總結

以上是生活随笔為你收集整理的[2020-11-30 contest]数列(矩阵加速),秘密通道(dijkstra最短路)小X游世界树(换根dp),划分(数学)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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