【省內訓練2018-09-13】Hamilton Path
【思路要點】
有一種樸素的 的做法,首先列舉路徑開始的位置,那麼從這個點開始的每一個點必須只存在一個沒有被訪問的後繼,因此我們可以在 的時間內確定一個起始點出發是否有解,若有解,我們會找到一組唯一的解。
對於有哈密爾頓迴路的資料,若我們先找到了一條哈密爾頓迴路,那麼對於一條非環邊,它會使一個區間內的點無法作為起始點,如圖中的紅點,因此最終可行的起始點一定是環上的一個區間,我們顯然能線上性的時間內找到可行的起始點區間並計算答案。
注意到一個起始點出發若不能夠找到解,那麼從它經過的點出發同樣不能夠找到解,如果我們將點集
一下,每次選取起始點都會期望刪除一半的錯誤起始點,因此期望 次選取起始點後,我們能夠找到哈密爾頓迴路或者沒有起始點可以選擇,期望時間複雜度 。在比賽時筆者發現加上這個優化後程序獲得了 (下文程式碼就是這個做法)。
事實上,當不存在哈密爾頓迴路,但問題有解的情況下,問題的解的數量不超過 (下文將給予說明)。這個演算法同樣能夠在 的期望時間複雜度內給出結果。但這個演算法在不存在哈密爾頓迴路,且問題無解的情況下的時間複雜度可能退化,考慮如下資料,該演算法將退化至
:
其實也是存在解決方法的,由於有解的時候存在 的期望時間複雜度,所以若一個數據跑了很久沒有出解,那這個資料的答案就是無解。總時間複雜度 。以上是筆者在考場上的亂搞做法,下面我們來講這個題的正解。
首先,若存在點 ,滿足 ,其中 表示 的入度, 表示 的出度,那麼 的後繼結點必然是 唯一的出點,我們把 和 的出點縮在一起考慮。
注意到此時若圖中存在哈密爾頓迴路,那麼縮點後的圖去掉自環後將是一個環,或者出現雙向邊(此時問題無解),接下來我們認為圖中不存在哈密爾頓迴路。
此時,剩餘的點中,若存在 的點,那麼它一定是起始點,若有多個這樣的點問題顯然無解。
我們將剩餘的點分為三類: 的點稱為 類點, 的點稱為 類點, 的點稱為 類點, 類點顯然只能有一個。
只有 類點可能成為起始點,其餘點由於出度不對,無法成為起始點。
一個能夠作為起始點的 類點應當滿足沿著它的出邊走到的第一個點非 類點為 類點,且該 類點存在一條指向該 類點的出邊,如下圖。
注意到該圖中 點沒有其他的入邊,也就是說,若 點不是起始點,這樣的結構一旦進入,就無法走出去了,因此這樣的結構在圖中至多存在兩個,否則問題無解。
那麼,我們只需要暴力檢驗這兩個起始點是否能夠得到一組解即可。
時間複雜度 。
【程式碼】
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 5e5 + 5;
const int MAXM = 1e6 + 5;
const int P = 1e9 + 7;
template <typename T> void read(T &x) {
x = 0; int f = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -f;
for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
bool solved, vis[MAXN], ban[MAXN];
int n, m, bit[MAXN];
int x[MAXM], y[MAXM];
int p[MAXN], home[MAXN];
int cnt, ans[MAXN];
vector <int> a[MAXN];
void check(int pos, int sum) {
bool loop = false;
for (unsigned i = 0; i < a[pos].size(); i++)
if (a[pos][i] == p[1]) loop = true;
if (!loop) {
ans[++cnt] = sum;
return;
}
solved = true;
static int d[MAXN * 2];
for (int i = 1; i <= 2 * n; i++)
d[i] = 0;
cnt = 0;
for (int i = 1; i <= n; i++) {
ans[i] = -1;
home[p[i]] = i;
}
for (int i = 1; i <= m; i++) {
int tx = home[x[i]], ty = home[y[i]];
if (tx + 1 == ty || (tx == n && ty == 1)) continue;
if (tx < ty) tx += n;
d[ty + 1]++, d[tx + 1]--;
}
for (int i = 1; i <= 2 * n; i++)
d[i] += d[i - 1];
for (int i = 1; i <= n; i++) {
if (d[i] == 0 && d[i + n] == 0) {
cnt++;
ans[p[i]] = sum;
}
sum = (sum - 1ll * bit[n - 1] * p[i] % P + P) % P;
sum = (sum * 10ll + p[i]) % P;
}
writeln(cnt);
for (int i = 1; i <= n; i++)
if (ans[i] != -1) {
write(ans[i]);
putchar(' ');
}
printf("\n");
return;
}
void work(int pos, int sum) {
for (int i = 1; i <= n; i++) {
sum = (sum + 1ll * bit[n - i] * pos) % P;
p[i] = pos;
if (i == n) {
check(pos, sum);
for (int j = 1; j <= n; j++)
vis[j] = false;
return;
}
vis[pos] = true;
int dest = 0;
for (unsigned j = 0; j < a[pos].size(); j++)
if (!vis[a[pos][j]]) {
if (dest == 0) dest = a[pos][j];
else {
for (int k = 1; k <= i; k++) {
vis[p[k]] = false;
ban[p[k]] = true;
}
return;
}
}
if (!dest) {
for (int k = 1; k <= i; k++) {
vis[p[k]] = false;
ban[p[k]] = true;
}
return;
}
pos = dest;
}
}
int main() {
int T; read(T);
while (T--) {
read(n), read(m);
bit[0] = 1;
for (int i = 1; i <= n; i++) {
a[i].clear(), ban[i] = false;
bit[i] = bit[i - 1] * 10ll % P;
}
for (int i = 1; i <= m; i++) {
read(x[i]), read(y[i]);
a[x[i]].push_back(y[i]);
}
for (int i = 1; i <= n; i++) {
sort(a[i].begin(), a[i].end());
a[i].resize(unique(a[i].begin(), a[i].end()) - a[i].begin());
}
cnt = 0, solved = false;
for (int i = 1; i <= n; i++) {
if (!ban[i]) work(i, 0);
if (solved) break;
}
if (!solved) {
printf("%d\n", cnt);
if (cnt >= 1 && cnt <= n) {
for (int i = 1; i <= cnt; i++)
printf("%d ", ans[i]);
printf("\n");
}
}
}
return 0;
}
【標程】
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
// head
const int N=501000;
VI e[N],r[N];
int he[N];
int n,m,u,v,vis[N],mt,ret[N],_;
int f[N],pre[N],nxt[N],t[N];
int ind[N],oud[N],cnt[N];
相關推薦
【省內訓練2018-09-13】Hamilton Path
【思路要點】
有一種樸素的 O(N∗M)O(N∗M) 的做法,首先列舉路徑開始的位置,那麼從這個點開始的每一個點必須只存在一個沒有被訪問的後繼,因此我們可以在 O(M)O(M) 的時間內確定一個起始點出發是否有解,若有解,我們會找到一組唯一的解。
【省內訓練2018-10-28】網友串
【思路要點】
首先,奇數和偶數可以分開處理,最後再將答案卷積得到最終答案。
預處理每一對網友數是否能夠構成混沌串。
我們用三元組
(
【省內訓練2018-10-28】排序二叉樹
【思路要點】
若將一個序列按照元素大小排序,那麼其對應的排序二叉樹即為插入時間對應的笛卡爾樹,並且,被刪除的元素可以視作插入時間為正無窮的元素。
一個點在排序二叉樹上所有的祖先即其左側/右側對應的所有插入時間為後/字首最小值的點。
離線操作,對權值離
【省內訓練2018-10-26】矩陣
【思路要點】
用十字連結串列維護整個矩陣,操作時將被操作的子矩形提取出來,改變周圍一圈點的連邊,再拼接回去即可,單次操作修改的邊數是
O
【省內訓練2018-10-26】網友數
【思路要點】
首先,當
k
≥
9
【省內訓練2018-10-26】遊走
【思路要點】
考慮一個指數暴力,首先列舉每一個位置選擇 “見好就收” 還是 “得寸進尺” 。
記
E
【省內訓練2018-11-25】Factorization
【思路要點】
用類似
M
i
【省內訓練2018-11-25】Decomposition
【思路要點】
考慮計算每一個數的貢獻,即列舉一個數
i
i
【省內訓練2018-11-23】Bishop
【思路要點】
先考慮一個子問題,在
N
∗
【省內訓練2018-11-23】Palindrome
【思路要點】
考慮從兩端向中間
d
p
【省內訓練2018-11-23】Graph
【思路要點】
離線詢問,為每一條邊找到一個刪除時間。
將過程倒過來,按照刪除時間倒序加入每一條邊。
我們將加入的邊分為兩類,加入後連線兩個不同的聯通塊的稱為樹邊,剩餘的邊稱為非樹邊。
顯然,樹邊的加入不會產生新的雙連通分量,因此,我們可以預先
【校內訓練2018-10-19】Gift
【思路要點】
首先,若不存在
0
0
【校內訓練2018 10 19】貓哭 二分 / 貪心
題
給定一個大寫英文字母串,問最多能將原串分為多少個形如 CATCATCAT 或 TATTATTAT 的子序列?
如 CATATCATATCATAT,僅能分出一個。而 CATTATCATTATCATTA
2018/09/13《塗抹MySQL》【MySQL復制特性】學習筆記(六)
ref nor affect 來看 like 從數據 b2c img 密碼 推薦一首歌
- 《可不可以》張紫豪
好吧,隨便從排行榜上找了一首
讀
第十一章《MySQL的復制特性》
總結
1:復制(Replication) 應用場景?
- 提高性能 (通過
【躍遷之路】【585天】程式設計師高效學習方法論探索系列(實驗階段342-2018.09.13)
@(躍遷之路)專欄
【躍遷之路】獎勵金計劃正式開始
從2018.7.1起,【躍遷之路】獎勵金計劃正式起航,從今以後,, 每月1日,我會將自己個人上月收入的1%計入【躍遷之路】獎勵金池,積累到足夠金額後,將適時用於獎勵那些雖然身處困境,卻依然不放棄努力,通過堅持,不斷
【2018.03.13】Linux基本指令+Vim編輯器+重定向+正則表達式
list lis 3.1 end 邊界 多字節 並不會 模式 oca 一、Linux基本指令
find
-name:按照文件名進行查找
文件搜索
不設置參數時,find默認在當前目錄下查找其子目錄及文件,並顯示查找的全部子目錄及文件
-size:按照文件大
JS 2018.09.13訓練題筆記
1、JavaScript程式中,alert(undefined == null)的輸出結果是 ture;
解析:undefined值是派生自null值的,因此ECMA-262規定對它們的相等性測試要返回true。
【度小滿2018-09-26線上筆試】ONU
題目描述
ONU是一種新型桌遊,一副牌有若干種花色,總共N張,且每種花色的牌的張數一樣。現在每次給定N,M,表示這幅總共N張的牌至少有M種花色,請問這副牌可能的花色有多少種?
輸入
共一行,兩個整數N,M。(1<=N<=1012,0<=M<=1012)
【華為2018-09-15線上筆試】查詢最後一個只出現一次的字元
題目描述
在一個給定的字串中找到最後一個只出現一次的字元。
輸入描述:
一個定長的字串,其中字元沒有順序,字元可以重複/
輸出描述:
一個字元。最後一個只出現一次的字元;如果字元的出現次數都是
【華為2018-09-15線上筆試】十進位制20位資料乘法
題目描述
十進位制20位資料乘法
輸入描述:
兩個不超過20位都不為0的十進位制字串
輸出描述:
字串相乘結果
示例1
輸入
20000000000000000000
30000000