以为150要垫底了,没想到还有高手。
送信卒
签,没一会就写完但因为交的太晚被猫娘抢了首A。恼火。
简要题意
给一个\(n\times m(n,m\le 100)\)的网格图,左右走的代价为\(1\),上下走的代价为\(k\),求最小的\(k\),使得\((sx,sy)\)到\((tx,ty)\)的代价恰好为\(s(s\le 10^5)\)。数据保证有解。
solution
目前有\(O(n+m)\log m\log s\)的std解法和\(O(n^4)\)的反向爆标解法,但因为跑得慢,所以不说了。
发现当\(k\)越大时,最短路越大,所以考虑二分\(k\),如果最短路\(\ge s\),则记录即可,注意一下精度问题吧,因为卡错解的时候不小心吧\(O(n^4)\)的精度卡了。
点此查看代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCAL
FILE *InFile = freopen("in.in","r",stdin),*OutFile = freopen("out.out","w",stdout);
#else
// FILE *InFile = stdin,*OutFile = stdout;
FILE *InFile = freopen("msg.in","r",stdin),*OutFile = freopen("msg.out","w",stdout);
#endif
using ll = long long;using ull = unsigned long long;
using db = double;using ldb = long double;
const int N = 1e5 + 10,RN = 110;
const db eps = 1e-7;
template<size_t N,size_t M>
struct Graph{
struct EDGE{int to,n;db w;}e[M];
int h[N],cnt;
inline void add(int u,int v,db w){e[++cnt] = {v,h[u],w};h[u] = cnt;}
inline void Add(int u,int v,db w){add(u,v,w);add(v,u,w);}
#define repe(i,x,y,g) for(int i = g.h[x],y = g.e[i].to;i;i = g.e[i].n,y = g.e[i].to)
};Graph<N,N*5> g;
int n,m,sx,sy,tx,ty,st,ed,a[RN][RN];
db s,dist[N];
bitset<N> vis;
vector<int> up;
inline int gp(int x,int y){return (x-1)*m+y;}
inline void dijkstra(int s){
rep(i,1,gp(n,m),1) dist[i] = INT_MAX,vis[i] = false;
priority_queue<pair<db,int>,vector<pair<db,int> >,greater<pair<db,int> > > q;
dist[s] = 0;q.push(make_pair(dist[s],s));
while(q.size()){
int x = q.top().second;q.pop();
if(vis[x]) continue;vis[x] = true;
repe(i,x,y,g){
if(dist[y] > dist[x] + g.e[i].w){
dist[y] = dist[x]+g.e[i].w;
q.push(make_pair(dist[y],y));
}
}
}
}
inline bool check(db mid){
for(auto i:up) g.e[i].w = mid;
dijkstra(st);
return dist[ed] >= s + eps;
}
inline void solve(){
cin>>n>>m>>sx>>sy>>tx>>ty;
st = gp(sx,sy),ed = gp(tx,ty);
rep(i,1,n,1) rep(j,1,m,1) cin>>a[i][j];
cin>>s;
auto pd = [&](int x,int y){
return 1 <= x && x <= n && 1 <= y && y <= m && a[x][y] == 0;
};
rep(i,1,n,1) rep(j,1,m,1){
if(a[i][j]) continue;
if(pd(i,j-1)){
// cerr<<i<<' '<<j<<'\n';
g.Add(gp(i,j),gp(i,j-1),1);
}
if(pd(i-1,j)){
// cerr<<i<<' '<<j<<'\n';
g.Add(gp(i,j),gp(i-1,j),0),
up.push_back(g.cnt),up.push_back(g.cnt-1);
}
}
// cerr<<check(0.667)<<'\n';
// exit(0);
db l = 0,r = s,ans = 0;
while(l + eps <= r){
db mid = (l + r)/2;
if(check(mid)) ans = mid,r = mid;
else l = mid;
}
cout<<fixed<<setprecision(3)<<ans<<'\n';
}
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
solve();
}
共轭树图
赛时推出结论来了不会打\(dp\)我是SB
简要题意
太长了不写了。
solution
发现满足上述条件的\(G\)是可生成的时,当且仅当:把\(G\)中的边画在原树上,形成的两条路径要么无交,要么为包含关系。
考虑设\(f_{x,i}\)表示以\(x\)为根的子树,而且\(x\)只被允许和它的第\(i\)个祖先在\(G\)中连边时,子树的方案数。有
\[f_{x,i}=\prod\sum_{j=1}^if_{y,i-j+2} \]发现后面的柿子用前缀和优化即可做到\(O(n^2)\)。
点此查看代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t; i += p)
#define drep(i,s,t,p) for(int i = s;i >= t; i -= p)
#ifdef LOCAL
FILE *InFile = freopen("in.in","r",stdin),*OutFile = freopen("out.out","w",stdout);
#else
// FILE *InFile = stdin,*OutFile = stdout;
FILE *InFile = freopen("reflection.in","r",stdin),*OutFile = freopen("reflection.out","w",stdout);
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
#define eb emplace_back
constexpr int N = 3e3 + 10,mod = 998244353;
int n,f[N][N];
vector<int> e[N];
void dfs(int x,int fa){
for(int y:e[x]) if(y ^ fa) dfs(y,x);
rep(i,1,n,1){
f[x][i] = 1;
for(int y:e[x]) if(y ^ fa) f[x][i] = 1ll*f[x][i]*f[y][i+1]%mod;
}
rep(i,3,n+1,1) f[x][i] = (f[x][i] + f[x][i-1])%mod;
}
inline void solve(){
cin>>n;
rep(i,1,n-1,1){int u,v;cin>>u>>v;e[u].eb(v);e[v].eb(u);}
dfs(n,0);cout<<f[n][1];
}
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
solve();
}
摸鱼军训
简要题意
给定一个长度为\(n(n\le 5\times10^5)\)的排列,有\(q(q\le 5\times 10^5)\)次询问,每次给定\(k,x(k,x\le 5\times 10^5)\),求\(k\)轮冒泡排序后\(x\)所在的位置。
solution
记\(r_x\)表示在\(x\)前中比\(x\)大的数的个数。
如果\(r_x\ge k\),那么\(x\)会去到\(i-k\)的位置,反之,那么剩下的就会填入剩余的空位中。
先求出\(r\)数组后,将询问离线,然后就转化成了单点取反,区间求和,求第\(k\)个\(0/1\)的位置的数据结构,这就是个线段树,最后一个操作线段树上二分即可。
点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
using namespace __gnu_pbds;
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCAL
FILE *InFile = freopen("in.in","r",stdin),*OutFile = freopen("out.out","w",stdout);
#else
// FILE *InFile = stdin,*OutFile = stdout;
FILE *InFile = freopen("bubble.in","r",stdin),*OutFile = freopen("bubble.out","w",stdout);
#endif
using ll = long long;using ull = unsigned long long;
using db = double;using ldb = long double;
const int N = 5e5 + 10;
struct Segment_Tree{
struct segment_tree{
int l,r,val;
#define l(x) tree[x].l
#define r(x) tree[x].r
#define val(x) tree[x].val
}tree[N<<2];
inline void pushup(int k){val(k) = val(k<<1)+val(k<<1|1);}
void build(int k,int l,int r){
l(k) = l,r(k) = r;
if(l == r) return val(k) = 0,void();
int mid = (l + r) >> 1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
pushup(k);
}
void upd(int k,int pos,int val = 1){
if(l(k) == r(k)) return val(k) = 1,void();
int mid = (l(k) + r(k)) >> 1;
if(pos <= mid) upd(k<<1,pos,val);else upd(k<<1|1,pos,val);
pushup(k);
}
int qryk(int k,int p){
if(l(k) == r(k)) return l(k);
int ls = k<<1;
if(p - val(ls) <= 0) return qryk(k<<1,p);
else return qryk(k<<1|1,p-val(ls));
}
int qrys(int k,int l,int r){
if(l <= l(k) && r(k) <= r) return val(k);
int mid = (l(k) + r(k)) >> 1,res = 0;
if(l <= mid) res += qrys(k<<1,l,r);
if(r > mid) res += qrys(k<<1|1,l,r);
return res;
}
}T;
struct BIT{
int mx,tree[N];
inline int lb(int x){return (x&(-x));}
inline void upd(int pos,int val){rep(i,pos,mx,lb(i)) tree[i] += val;}
inline int qry(int pos){int res = 0;drep(i,pos,1,lb(i)) res += tree[i];return res;}
}bit;
struct Q{int k,x,id;}q[N];
int n,m,pos[N],ans[N],a[N],num[N];
inline void solve(){
cin>>n;T.build(1,1,n);bit.mx = n;
rep(i,1,n,1) cin>>a[i],pos[a[i]] = i;
rep(i,1,n,1) bit.upd(a[i],1),num[i] = i - bit.qry(a[i]);
cin>>m;rep(i,1,m,1) cin>>q[i].k>>q[i].x,q[i].id = i;
sort(q+1,q+1+m,[](Q x,Q y){return x.x > y.x;});
int now = n;
rep(i,1,m,1){
while(now > q[i].x) T.upd(1,pos[now]),now--;
if(num[pos[q[i].x]] >= q[i].k) ans[q[i].id] = pos[q[i].x] - q[i].k;
else{
if(q[i].k > T.tree[1].val) ans[q[i].id] = q[i].x;
else ans[q[i].id] = T.qryk(1,q[i].k) - q[i].k;
}
}
rep(i,1,m,1) cout<<ans[i]<<'\n';
}
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
solve();
}
神奇园艺师
不会。
本来想写鲜花的但是电脑死了,都没了,不写了。
p