多校A层冲刺NOIP2024模拟赛09

又双叒叕垫底啦

rank 4,T1 50,T2 100,T3 39,T4 35。

accoder 上同分,rank 20

排列最小生成树 (pmst)

打的\(O(n^2 \log n^2)\)暴力

发现总是存在⼀颗⽣成树,使得⽣成树⾥的所有边的边权都⼩于\(n\)
考虑 Kruskal 的过程,我们只需要留下那些边权⼩于\(n\)的边。

然后用桶排序即可。

点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
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)
#define Infile(x) freopen(#x".in","r",stdin)
#define Outfile(x) freopen(#x".out","w",stdout)
#define Ansfile(x) freopen(#x".ans","w",stdout)
#define Errfile(x) freopen(#x".err","w",stderr)
#ifdef LOCAL
    FILE *InFile = Infile(in),*OutFile = Outfile(out);
    // FILE *ErrFile = Errfile(err);
#else
    FILE *InFile = Infile(pmst),*OutFile = Outfile(pmst);
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
const int N = 5e4 + 10;
#define pii pair<int,int>
#define mk make_pair
int n,len,fa[N];
vector<pii> ct[N];
inline int get_fa(int x){while(x != fa[x]) x = fa[x] = fa[fa[x]];return x;}
int cx[N],cy[N];
inline void solve(){
    cin>>n;
    rep(i,1,n,1){int x;cin>>x;cx[i] = x;cy[x] = i;}
    len = sqrt(n);
    rep(i,1,n,1){
        rep(j,i+1,min(i+len,n),1){
            int val;
            val = abs(cx[i]-cx[j])*(j-i);
            if(val <= n) ct[val].emplace_back(mk(i,j));
            val = abs(cy[i]-cy[j])*(j-i);
            if(val <= n) ct[val].emplace_back(mk(cy[i],cy[j]));
        }
    } 
    int tot = 0;
    rep(i,1,n,1) fa[i] = i;
    ll ans = 0;
    rep(i,1,n,1) for(auto j:ct[i]){
        int x = j.first,y = j.second;
        x = get_fa(x),y = get_fa(y);
        if(x == y) continue;
        fa[x] = y,ans += i,tot++;
        if(tot == n-1) break;
    }
    cout<<ans<<'\n';
}
signed main(){
    cin.tie(nullptr)->sync_with_stdio(false);
    solve();
}

卡牌游戏 (cardgame)

签。

发现循环节是\(lcm\),然后找规律即可。大体的规律就是\(\forall i\in [1,\gcd(n,m)]\)所有的\(\frac{k_1}{i}=0,\frac{k_2}{i}=0 (1\le k_1\le n,1\le k_2\le m)\)都会组一次队。

然后对于每一个\(i\)处理,离散化后开个权值树状数组维护即可。时间复杂度\(O(n\log n)\)

注意不能用memset清空

点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
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)
#define Infile(x) freopen(#x".in","r",stdin)
#define Outfile(x) freopen(#x".out","w",stdout)
#define Ansfile(x) freopen(#x".ans","w",stdout)
#define Errfile(x) freopen(#x".err","w",stderr)
#ifdef LOCAL
    FILE *InFile = Infile(in),*OutFile = Outfile(out);
    // FILE *ErrFile = Errfile(err);
#else
    FILE *InFile = Infile(cardgame),*OutFile = Outfile(cardgame);
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
#define int long long
const int N = 1e5 + 10;
int n,m,a[N],b[N],ans1,ans2,ans3;
#define eb emplace_back
struct BIT{
    int tree[N<<1],mx;
    inline int lowbit(int x){return (x&(-x));}
    inline void upd(int pos,int val){rep(i,pos,mx,lowbit(i)) tree[i] += val;}
    inline int qry(int pos){int res = 0;drep(i,pos,1,lowbit(i)) res += tree[i];return res;}
}T;
inline void get_ans(int &ans1,int &ans2,int &ans3){
    int gcd = __gcd(n,m);
    rep(i,1,gcd,1){
        int res = 0;
        rep(j,i,n,gcd) T.upd(a[j],1),res++;
        rep(j,i,m,gcd){
            ans2 += T.qry(b[j]-1);
            ans3 += T.qry(b[j]) - T.qry(b[j]-1);
            ans1 += res - T.qry(b[j]);
        }
        rep(j,i,n,gcd) T.upd(a[j],-1);
    }
    ans1 *= gcd;ans2 *= gcd;ans3 *= gcd;
}
inline void solve(){
    cin>>n>>m;
    rep(i,1,n,1) cin>>a[i];
    rep(i,1,m,1) cin>>b[i];
    vector<int> num;
    rep(i,1,n,1) num.eb(a[i]);rep(i,1,m,1) num.eb(b[i]);
    sort(num.begin(),num.end());
    num.erase(unique(num.begin(),num.end()),num.end());
    T.mx = num.size();
    rep(i,1,n,1) a[i] = lower_bound(num.begin(),num.end(),a[i]) - num.begin() + 1;
    rep(i,1,m,1) b[i] = lower_bound(num.begin(),num.end(),b[i]) - num.begin() + 1;
    if(n > m) swap(n,m),swap(a,b),get_ans(ans2,ans1,ans3);
    else get_ans(ans1,ans2,ans3);
    cout<<ans1<<'\n'<<ans2<<'\n'<<ans3<<'\n';
}
signed main(){
    cin.tie(nullptr)->sync_with_stdio(false);
    solve();
}

比特跳跃 (jump)

诡异建图题,没调出来,打的暴力与特殊性质。

\(S=1\)时,发现只有\(n=(2^k)-1\)时,到第\(n\)个点的最短路才有权值。

\(S=2\)时,发现只需要考虑改变一位即可。

\(s=3\)时,发现\(x|y\ge max(x,y)\),所以如果跳跃到\(i\)的如果不是从\(j(j|i=i)\)过来的,那么一定不如从1跳过来。然后只需要考虑改变一位即可,用上拓展域跑一遍即可。

点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
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)
#define Infile(x) freopen(#x".in","r",stdin)
#define Outfile(x) freopen(#x".out","w",stdout)
#define Ansfile(x) freopen(#x".ans","w",stdout)
#define Errfile(x) freopen(#x".err","w",stderr)
#ifdef LOCAL
    FILE *InFile = Infile(in),*OutFile = Outfile(out);
    // FILE *ErrFile = Errfile(err);
#else
    FILE *InFile = Infile(jump),*OutFile = Outfile(jump);
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
const int N = 2e6 + 10;
struct Edge{
    struct EDGE{int to,next;ll w;}edge[N<<1];
    int head[N],cnt;
    inline void Add(int u,int v,ll w){
        // cerr<<u<<' '<<v<<' '<<w<<'\n';
        edge[++cnt] = {v,head[u],w};head[u] = cnt;
        edge[++cnt] = {u,head[v],w};head[v] = cnt;
    }
    inline void add(int u,int v,ll w){
        edge[++cnt] = {v,head[u],w};head[u] = cnt;
    }
    #define repe(i,x,y,e) for(int i = e.head[x],y = e.edge[i].to; i;i = e.edge[i].next)
}g;
ll dist[N];
bitset<N> vis;
int n,m,s,k;
#define pii pair<ll,int>
#define mk make_pair
inline void dijkstra(int s){
    priority_queue<pii,vector<pii>,greater<pii> > q;
    memset(dist,0x3f,sizeof dist);
    dist[s] = 0;q.push(mk(dist[s],s));
    // cout<<'\n';
    while(q.size()){
        int x = q.top().second;q.pop();
        // cerr<<x<<'\n';
        if(vis[x]) continue;
        vis[x] = true;
        for(int i = g.head[x]; i;i = g.edge[i].next){
            int y = g.edge[i].to;
            if(dist[y] > dist[x] + g.edge[i].w){
                dist[y] = dist[x] + g.edge[i].w;
                q.push(mk(dist[y],y));
            }
        }
    }
}
int sta[N],id[N];
inline void solve(){
    cin>>n>>m>>s>>k;
    int lg = log2(n);
    rep(i,1,m,1){
        int u,v,w;cin>>u>>v>>w;
        g.Add(u,v,w);
    }
    if(s == 1){
        g.Add(1,n+1,0);
        rep(i,2,n,1) rep(j,0,lg,1)
            if(!(i&(1<<j))) g.Add(i,n+1,0);
    }
    if(s == 2){
        rep(i,0,n,1) rep(j,0,lg,1){
            if((i^(1<<j))&&(i^(1<<j)) <= n)
                g.Add(i,i^(1<<j),1ll*k*(1<<j));
        }
    }
    if(s == 3){
        rep(i,1,n,1) sta[i] = i+1;
        int tt = n;
        sort(sta+1,sta+1+n,[](int x,int y){return __builtin_popcount(x) < __builtin_popcount(y);});
        rep(i,1,n,1) g.Add(1,i,1ll*k*(i|1));
        rep(i,1,n,1){
            int s = sta[i];
            id[s] = ++tt;
            g.add(s,id[s],0);g.add(id[s],s,1ll*s*k);
            rep(j,0,lg,1) if(s&(1<<j)) g.add(id[s^(1<<j)],id[s],0);
        }
    }
    dijkstra(1);
    rep(i,2,n,1) cout<<dist[i]<<' ';
}
signed main(){
    cin.tie(nullptr)->sync_with_stdio(false);
    solve();
}

区间 (interval)

打的\(O(n^2+q)\)的。滚去学DS的,等学到再打。

posted @ 2024-10-20 10:23  CuFeO4  阅读(51)  评论(2)    收藏  举报