時間剪枝
時間剪枝
- 很好用的唬爛方式
- 當你的方法是 TLE時可以試試看
signed main(){
double st=clock();
while((clock()-st)/CLOCKS_PER_SEC<=0.8) ...;
}- 給一個 \(n\) 點 \(m\) 邊的無向圖
- \(m=n-1 \lor n\)
- \(1\leq n \leq 10^5\)
- 每條邊有權重
- 求最長路徑
- 先考慮 \(m=n-1\), 那就會是樹
- 等價求樹直徑
- 可以 \(O(n)\) 計算
- 那 \(m=n\) 呢?
- 會類似水母圖
- 一個環上連著很多樹

- 樹直徑會做
- 如果把環上暴力拔一條邊也會剩下一棵樹
- 暴力枚舉環上每條邊拔掉做樹直徑 => TLE
- 一直隨機拔邊算答案(跑多久?時間剪枝)
- 據說隨機3次賽中就會過
- 時間剪枝當然不只這樣
- 當體感貪心算法是對的,但可能會因為一些特定構造讓你要跑多一點次數
- 重複貪心算法更新跑到時間限制
- 很像 bellman-ford更新
- 給定 \(n\times m\) 方格
- 一些方格是空白的(表示为
.),而一些方格是被填充的(表示为#)相鄰 # 代表是同一物體 - 之後全部會開始往下落,求最後結果
- \(1≤N\times M≤10^6\)


- 最直觀的想法會是甚麼?
- 從最下面的開始往上,對每一個位置去更新他所屬物體可以往下的距離。最後就按照每物體合法位移往下移動
- 吃 WA ?
- 兩塊的關聯性可能互相糾纏如下圖,可能不小心讓上面的超過下面
- 多跑幾次降低錯誤可能性 => 時間剪枝
#include<bits/stdc++.h>
#define int long long
#define Get(i,j) ((i-1)*m+j)
#define quick ios::sync_with_stdio(0);cin.tie(0);
#define rep(x,a,b) for(int x=a;x<=b;x++)
#define repd(x,a,b) for(int x=a;x>=b;x--)
#define lowbit(x) (x&-x)
#define sz(x) (int)(x.size())
#define F first
#define S second
#define all(x) x.begin(),x.end()
#define mp make_pair
#define eb emplace_back
using namespace std;
typedef pair<int,int> pii;
void debug(){
cout<<"\n";
}
template <class T,class ... U >
void debug(T a, U ... b){
cout<<a<<" ",debug(b...);
}
const int N=1e6+7;
const int INF=1e18;
int lp[N];
int lk[N];
int p[N];
int sz[N];
int add[N];
void init(int n){
rep(i,1,n) p[i]=i,sz[i]=1,add[i]=INF,sz[i]=1;
}
int fp(int x){
if(p[x]!=x) p[x]=fp(p[x]);
return p[x];
}
void Union(int a,int b){
a=fp(a),b=fp(b);
if(sz[a]<sz[b]) swap(a,b);
p[b]=a;
sz[a]+=sz[b];
}
signed main(){
quick
double st=clock();
int n,m;
cin>>n>>m;
vector<vector<bool> > v(n+5,vector<bool>(m+1));
vector<vector<int> > f(n+5,vector<int>(m+1));
init(n*m);
rep(i,1,n){
rep(j,1,m){
char c;
cin>>c;
v[i][j]=(c=='#');
}
}
rep(i,1,n){
rep(j,1,m){
if(!v[i][j]) continue;
if(v[i-1][j]) Union(Get(i,j),Get(i-1,j));
if(v[i][j-1]) Union(Get(i,j),Get(i,j-1));
}
}
vector<pii> traverse;
while((clock()-st)/CLOCKS_PER_SEC<=1.3){
rep(i,1,m) lp[i]=n+1,lk[i]=0;
repd(i,n,1){
rep(j,1,m) {
if(!v[i][j]) continue;
int k=fp(Get(i,j));
add[k]=min(add[k],lp[j]+add[lk[j]]-i-1);
lp[j]=i,lk[j]=k;
}
}
}
vector<vector<bool> > ans(n+5,vector<bool>(m+1));
rep(i,1,n){
rep(j,1,m){
if(v[i][j]){
int k=fp(Get(i,j));
ans[i+add[k]][j]=1;
}
}
}
rep(i,1,n){
rep(j,1,m) cout<<".#"[ans[i][j]];cout<<"\n";
}
}- 一條邊如果是第 \(k\) 次走到則其辛苦程度是 \(d(i,j)^k \mod P\) , \(P\)為質數
- 求從 \(s\) 走到 \(t\) 且路徑最大辛苦程度最小是多少
- \(n\leq 1000\)
- \(m\leq 3000\)
- \(0\leq d(i,j)<P\leq 10^5\)
- 根據費馬小定理知道 \(d(i,j)^{P-1} \equiv 1 \pmod{P}\)
- 所以至多走 \(P-1\) 步
- \(dis(i,j)\) 代表點 \(i\) 走 \(j\) 步的最大辛苦程度最小
- \(dis(i,j)=max(dis(k,j-1),d(k,j)^{P}\) , 可以 \(O(MP)\) dp更新 => TLE
- 體感上不需跑那麼多次,跑到時限 => AC
時間剪枝
By yuhung94
時間剪枝
- 178