XJOI 11.13
作者:互联网
T1
用单调队列求出可以涂色的 \(n-x+1\) 个区间的区间最小值,那么就是每次将一段区间内的数对一个数取 \(\max\),最后询问每个位置是多少。
显然用 set 维护一下就好了。这样形成了若干个连续段,每个段内所有位置被涂色的高度相等。对于一个长度为 \(len\) 的段,至少需要 \(\lceil len/x \rceil\) 次染色才能完成,于是第二问的答案就是 \(\sum_{i} \lceil len_i/x \rceil\)。
T2
可以发现一个位置可以和在它前面的任意多个位置异或,也可以选择不异或。于是维护线性基即可,因为线性基的任意一个子集能表示的数互不相同。
T3
考虑直接 bfs:用 \((u,dis,p)\) 三元组记录当前到达的点、边数和概率。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#define For(Ti,Ta,Tb) for(int Ti=(Ta);Ti<=(Tb);++Ti)
#define Dec(Ti,Ta,Tb) for(int Ti=(Ta);Ti>=(Tb);--Ti)
typedef long long ll;
typedef pair<int,double> pid;
const int N=5e4+5;
int n,m,dis[N];
double p[N];
vector<pid> g[N];
int main(){
ios::sync_with_stdio(false),cin.tie(nullptr);
freopen("wude.in","r",stdin);
freopen("wude.out","w",stdout);
cin>>n>>m;
For(i,1,m){
int u,v,w;
cin>>u>>v>>w;
g[u].emplace_back(v,w/100.),g[v].emplace_back(u,w/100.);
}
For(i,1,n) dis[i]=0x3f3f3f3f;
using Node=struct{int u,dis;double p;};
queue<Node> q;
q.push({1,0,1}),p[1]=1,dis[1]=0;
while(!q.empty()){
auto _=q.front();q.pop();
for(auto v_:g[_.u]){
int v=v_.first;double w=v_.second;
if(p[v]<_.p*w&&_.p*w>=.75){
p[v]=_.p*w,dis[v]=min(_.dis+1,dis[v]);
q.push({v,_.dis+1,p[v]});
}
}
}
For(i,1,n){
if(p[i]>=.75) cout<<dis[i]<<' ';
else cout<<"-1 ";
}
return 0;
}
不会证时间复杂度,但可以保证正确性:对于每个点,第一次扩展到它的一定是最短路,第二次一定是次短路,以此类推,可以保证路径最短。
标签:int,11.13,len,_.,XJOI,Ti,include,dis 来源: https://www.cnblogs.com/alan-zhao-2007/p/15571763.html