多校A层冲刺NOIP2024模拟赛21

以为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

image
image

posted @ 2024-11-12 21:38  CuFeO4  阅读(25)  评论(1编辑  收藏  举报