又双叒叕垫底啦
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的,等学到再打。
标签:int,rep,09,多校,long,num,using,NOIP2024,define From: https://www.cnblogs.com/hzoi-Cu/p/18486983