傳送門
文章目錄
題意:
構造一個圖,使其從111到nnn的路徑的長度與[L,R][L,R][L,R]中某個值一一對應,不能有兩條路徑長度一樣,且每個值都必須出現(xiàn)一次,每兩個點之間只能連一條邊。
n≤32n\le32n≤32,ai,bi≤na_i,b_i\le nai?,bi?≤n,1≤ci≤1e61\le c_i\le 1e61≤ci?≤1e6。
思路:
看到n≤32n\le 32n≤32,不難想到二進制拆分,我們分情況來討論。
(1)L=1,R=2k(1)\ \ L=1,R=2^k(1)??L=1,R=2k
對于這種情況,我們需要拿出來k+2k+2k+2個點,從111向[2,k+2][2,k+2][2,k+2]的點連邊權為111的邊,讓后對于后面的每一個位置iii,都向后連邊權為2i?22^{i-2}2i?2的邊,這樣就可以構造出[1,2k][1,2^k][1,2k]內的邊權了。
(2)L=1,R>1(2)\ \ L=1,R>1(2)??L=1,R>1
對于這種情況,我們依舊按照(1)(1)(1)的思路構造出[1,2k][1,2^k][1,2k]的邊權,讓后再新加一個點k+3k+3k+3,考慮用新的點來構造出來[2k+1,R][2^k+1,R][2k+1,R]的邊權。
對于RRR,他的二進制形式大概是這樣的100100100...100100100...100100100...,很明顯,我們可以根據(jù)111來分段,因為我們已經構造出來了[1,2i][1,2^i][1,2i],即[1,1000..][1,1000..][1,1000..],假設RRR的從低位到高位的第iii位(從000開始)是111,那么我們只需要從i+2i+2i+2的位置向k+3k+3k+3連一個RRR將iii位及其之后的數(shù)都變成000的邊權,但是這樣會有點問題,就是因為構造的是[1,2i][1,2^i][1,2i],缺少000,那么連完之后也就缺少后面全000的邊權。所以我們考慮將R?1R-1R?1之后建邊,在新邊的邊權都+1+1+1即可。
(3)L>1,R>1(3)\ \ L>1,R>1(3)??L>1,R>1
只需要在最后新加一個點,在原來的最后一個點向他連l?1l-1l?1的邊即可,轉化成情況(1)(1)(1)或(2)(2)(2)。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=1000010,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6;int l
,r
;
int tot
;
struct Node
{int a
,b
,w
;
}edge
[N
];void add(int a
,int b
,int c
)
{edge
[++tot
]={a
,b
,c
};
}int main()
{
cin
>>l
>>r
;puts("YES");int rr
=r
-l
+1;int k
=0;while((1<<k
)<rr
) k
++;if((1<<k
)==r
){int cnt
=k
+2;for(int i
=2;i
<=k
+2;i
++) add(1,i
,1);for(int i
=2;i
<=k
+2;i
++)for(int j
=i
+1;j
<=k
+2;j
++)add(i
,j
,1<<(i
-2));if(l
>1) add(cnt
,cnt
+1,l
-1),cnt
++;printf("%d %d\n",cnt
,tot
);for(int i
=1;i
<=tot
;i
++) printf("%d %d %d\n",edge
[i
].a
,edge
[i
].b
,edge
[i
].w
);}else {k
--;int cnt
=k
+3;for(int i
=2;i
<=k
+2;i
++) add(1,i
,1);for(int i
=2;i
<=k
+2;i
++)for(int j
=i
+1;j
<=k
+2;j
++)add(i
,j
,1<<(i
-2));add(1,k
+3,1);for(int i
=0;i
<=k
;i
++)if((rr
-1)>>i
&1)add(i
+2,k
+3,((rr
-1)>>(i
+1)<<(i
+1))+1);if(l
>1) add(cnt
,cnt
+1,l
-1),cnt
++;printf("%d %d\n",cnt
,tot
);for(int i
=1;i
<=tot
;i
++) printf("%d %d %d\n",edge
[i
].a
,edge
[i
].b
,edge
[i
].w
);}return 0;
}
總結
以上是生活随笔為你收集整理的Codeforces Round #700 (Div. 1) C. Continuous City 构造 + 二进制的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。