首页 > 其他分享 >省选联测1

省选联测1

时间:2024-12-28 19:19:45浏览次数:6  
标签:dist 省选 rep long int 联测 freopen using

hahaha,太菜了,成功垫底力。

rank 3,T1 100pts,T2 0 pts,T3 0pts.

T1好像是神必贪心,写了个不知道对不对的做法,反正过了大样例,就这样吧。

T2不会,写了个\(2^n\times n\log m\)的暴力,可能是dp or 图论?

T3没读懂题。

总结:菜。

upd:T1过了,T2边权只有0/1我打什么dijkstra啊?T3是送分题?

interval

题意简述

给 \(n(n\le 5\times 10^5)\) 个区间,求最多能选出多少对区间,使得每对中的两个区间不交,值域\(10^9\)。

solution

考虑当前有一个区间\(c[l_c,r_c]\),如果有能和它匹配的,那么直接匹配,反之,那么看它能不能抢别人的。

考虑什么时候它能抢别人的。假设有两个区间\(b[l_b,r_b],a[l_a,r_a]\)已经配对\((r_a<l_b,r_a<l_c)\),假如\(c\)抢了\(a\)更优,那么当且仅当\(r_b<r_c\)。证明的话,考虑贪心,如果又有一个区间\(d[l_d,r_d]\),若\(r_b<r_c<l_d\),那么抢不抢都一样,若\(r_b<l_d<r_c\),那么抢了以后\(b\)就可以和\(d\)配对更优,若\(l_d<r_b<r_c\),那么拿不拿无影响。综上,此时\(c\)抢\(b\)一定不劣。

然后用个优先队列维护就行,时间复杂度\(O(n\log n)\)。

code
#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
    auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
    // auto Err = freopen("err.err","w",stderr);
#else
    auto I = freopen("interval.in","r",stdin),O = freopen("interval.out","w",stdout);
#endif
using ll = long long;using ull = unsigned long long;
using db = long double;using ldb = long double;
#define pii pair<int,int>
#define mk make_pair
#define ep emplace
const int N = 1e6 + 10;
int n;pii a[N];
struct node{
    int r,id,to;
    node(){};node(int R,int I,int T):r(R),id(I),to(T){}
    bool operator < (const node &x) const {return r == x.r?id < x.id:r < x.r;}
};set<node> st;
priority_queue<pii,vector<pii>,greater<pii> > uud;
signed main(){
    cin.tie(nullptr)->sync_with_stdio(false);
    cin>>n;rep(i,1,n,1) cin>>a[i].first>>a[i].second;
    sort(a+1,a+1+n,[](pii a,pii b){return a.first == b.first?a.second < b.second:a.first < b.first;});
    rep(i,1,n,1){
        bool flag = false;
        if(st.empty() && uud.empty()){uud.ep(a[i].second,i);continue;}
        else if(uud.size()){
            if(uud.top().first < a[i].first){
                int p = uud.top().second;
                st.ep(a[i].second,i,p);
                uud.pop();flag = true;
            }
        }
        if(flag) continue;
        if(st.size()){
            auto it = st.begin();
            if(it->r > a[i].second){uud.ep(a[i].second,i);continue;}
            int id1 = it->id,id2 = it->to;
            st.erase(node(a[id1].second,id1,id2));
            uud.emplace(a[id1].second,id1);
            st.ep(a[i].second,i,id2);
        }
        else uud.ep(a[i].second,i);
    }
    cout<<st.size()<<'\n';
}

apers

题意简述

给定一个\(n(n\le 200)\)个节点的有向图\(G\),有\(m(m\le 500)\)条边,每个节点被标记的代价为\(c_i(c_i\le 10^7)\),求出从\(s\rightarrow t\)的所有路径上,至少有\(k(k\le 5)\)个节点被标记的最小代价。

solution

最小割板子。

发现\(k\)很小,考虑建分层图,第\(i\)层表示踩了\(i\)颗雷。那么就要保证踩完一颗雷后就向上移动一层,所以第\(i\)层的\(x\)和第\(i+1\)层的\(x\)连一条\(inf\)的边。

但是这是不完善的,还没有将权值赋进去,考虑拆点,具体的,将第\(i\)层的点\(x\)拆成两个点\((x,i,0),(x,i,1)\),将\((x,i,0)\)和\((x,i,1)\)中连一条\(c_x\)的边。

显然不会重复踩同一颗雷,所以将\((x,i,1),(x,i+1,1)\)之间连一条\(inf\)的边。走到终点后不会继续走,所以将所有的\((t,i,0)\)和\((t,k,0)\)连一条\(inf\)的边,然后跑一个以\((s,1,0)\)为源点,以\((t,k,1)\)为汇点的最小割就行了。

算出来是过不去的,但是信仰一发就过了。

code
#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
    auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#else
    // auto I = stdin,O = stdout;
    auto I = freopen("apers.in","r",stdin),O = freopen("apers.out","w",stdout);
#endif
using ll = long long;using ull = unsigned long long;
using db = long double;using ldb = long double;
const int N = 210,M = 510;
template<size_t N,size_t M>
struct Graph{
    struct Edge{int to,n;ll w;}e[M];
    int h[N],ct = 1;
    void add(int u,int v,ll w){e[++ct] = {v,h[u],w};h[u] = ct;}
#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*100,M*10000> g;
vector<int> e[N];
int n,m,k,s,t,c[N];bool pd[N][N];
int mp[N][10][2],tot;//第 i 个点在第 k 层时,i 0/1 的编号
int dist[N*10*2],now[N*10*2];
bool judge(){
    bitset<N> vis;
    queue<pair<int,int> > q;q.emplace(s,1);vis[s] = true;
    while(q.size()){
        int x = q.front().first,dis = q.front().second;q.pop();
        for(auto y:e[x]){
            if(vis[y]) continue;
            vis[y] = true;
            int dist = dis + 1;
            q.emplace(y,dist);
            if(y == t){
                if(dist < k) return false;
                else return true;
            }
        }
    }
    return false;
}
bool bfs(int s = s){
    memset(dist,0,sizeof dist);
    queue<int> q;q.push(s);dist[s] = 1;now[s] = g.h[s];
    while(q.size()){
        int x = q.front();q.pop();
        repe(i,x,y,g){
            ll w = g.e[i].w;
            if(dist[y] || !w) continue;
            q.push(y);now[y] = g.h[y];
            dist[y] = dist[x] + 1;
            if(y == t) return true;
        }
    }
    return false;
}
ll dinic(int x,ll flow){
    if(x == t) return flow;
    ll res = 0;
    for(int i = now[x]; i;i = g.e[i].n){
        int y = g.e[i].to;
        ll w = g.e[i].w;
        if(!w) continue;
        if(dist[y] != dist[x] + 1) continue;
        ll k = dinic(y,min(flow,w));
        if(!k) dist[y] = 0;
        g.e[i].w -= k;g.e[i^1].w += k;
        res += k,flow -= k;
    }
    return res;
}
signed main(){
    cin.tie(nullptr)->sync_with_stdio(false);
    cin>>n>>m>>k>>s>>t;rep(i,1,n,1) cin>>c[i];
    rep(k,1,6,1) rep(i,1,n,1) rep(j,0,1,1) mp[i][k][j] = ++tot;
    rep(test,1,m,1){
        int u,v;cin>>u>>v;
        if(pd[u][v]) continue;pd[u][v] = true;
        e[u].emplace_back(v);
        rep(i,1,k,1)
            g.add(mp[u][i][1],mp[v][i][0],1e18),
            g.add(mp[v][i][0],mp[u][i][1],0);
    }
    if(!judge()) cout<<-1,exit(0);
    rep(j,1,k,1) rep(i,1,n,1)
        g.add(mp[i][j][0],mp[i][j][1],c[i]),g.add(mp[i][j][1],mp[i][j][0],0);
    rep(j,1,k-1,1) rep(i,1,n,1)
        g.add(mp[i][j][0],mp[i][j+1][1],1e18),
        g.add(mp[i][j+1][1],mp[i][j][0],0);
    rep(i,1,k-1,1) 
        g.add(mp[t][i][1],mp[t][k][1],1e18),g.add(mp[t][k][1],mp[t][i][1],0);
    s = mp[s][1][0];t = mp[t][k][1];
    ll ans = 0;
    while(bfs()){
        ll res = dinic(s,9e18);
        if(!res) break;
        ans += res;
    }
    cout<<ans<<'\n';
}

circles

(挂题解的话)
image

这真是送分题吗?

题意简述

现在有一张\(2n\)个点的二分图,左边\(n\)个点,右边\(n\)个点。其中左边第\(i\)个点与右边\(1\sim a_i\)个点有边。

你需要求出图中总共有多少个不同的简单环。简单环在这里指一个点只被经过至多一次的环。

答案对\(10^9+7\)取模。

solution

先将所有\(a_i\)排序。

对于一个环而言,如果只保留环中\([1,x]\)的点,那么这个环就被划分成若干条链。自然地,设\(f_{i,j}\)表示只保留\([1,i]\)范围内的点,形成\(j\)条链的方案数。

有初始状态\(f_{0,0} = 1\),考虑转移,就是加入点\(i\)会有什么影响。

若\(i\)为右部点,它要么会单独成链,要么和前面的一个链连在一起,即\(f_{i,j}=f_{i-1,j}+f_{i-1,j-1}\)。

若\(i\)为左部点,那么它要么连上一条链,要么将两条链合并成一条,即\(f_{i,j}=f_{i-1,j}+j\times (j-1)\times f_{i,j+1}\)。

将\(i\)和之前的一条链接起来成为一个环,将\(f_{i-1,1}\)累加进答案。

由于要剔除二元环,所以答案减去\(\sum\limits_{i=1}^na_i\)。

链是有序的,会将一个环计算两次,所以答案除以二。

code
#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
    auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#else
    // auto I = stdin,O = stdout;
    auto I = freopen("circles.in","r",stdin),O = freopen("circles.out","w",stdout);
#endif
using ll = long long;using ull = unsigned long long;
using db = long double;using ldb = long double;
const int N = 5010,mod = 1e9 + 7;
int n,a[N],f[N];
signed main(){
    cin.tie(nullptr)->sync_with_stdio(false);
    int ans = 0;
    cin>>n;rep(i,1,n,1) cin>>a[i],ans -= a[i];sort(a+1,a+1+n);
    f[0] = 1;
    rep(i,1,n,1){
        rep(j,a[i-1]+1,a[i],1) drep(k,j,1,1) f[k] = (f[k] + f[k-1])%mod;
        ans = (ans + f[1])%mod;
        rep(j,1,a[i],1) f[j-1] = (f[j-1] + 1ll*j*(j-1)*f[j]%mod)%mod;
    }
    cout<<1ll*ans*((mod+1)/2)%mod;
}

标签:dist,省选,rep,long,int,联测,freopen,using
From: https://www.cnblogs.com/hzoi-Cu/p/18637596

相关文章

  • 『联合省选2025集训』『图的连通性进阶』 知识点 总结
    前言若有长风绕旗,那便是我在想你了。这周讲了个图论连通性板块的一些进阶知识,周六全国第一给我们讲了一些树上的问题,感觉树剖板块实现难度较大,后面几道偏思维的题会有些许好转。这里就先写写连通性相关的进阶的一些知识点吧。主要涵盖:耳分解,双极定向,三连通分量和一些重要的......
  • 省选集训 Day 3
    学习了新知识:边三连通,耳分解,双极定向下面是一些基础练习。linkA挺不错的问题。考虑将一个点作为\(G_0\),一个个加入耳来构造边双连通图。容易设计\(f_S\)并枚举子集转移,复杂度\(O(3^nn^2)\)左右。太劣了,考虑将拼耳的过程纳入DP。设\(f_{S,j,k}\)为当前图已经填入......
  • 省选集训 Day 4
    省选集训Day4linkA联合省选2023D1T2纯树形dp做法B感觉是套路题啊。首先可以反应过来求出取到每个\(v\)的最大\(k\),然后做后缀\(\min\)使用二分查找算答案。将一条边\((x,y)\)的边权设为\(\gcd(w_x,w_y)\)枚举\(\gcd\),拿出所有边权是其倍数的边出来建立一个新的......
  • 省选模拟赛 1
    link期望100+100+15,实际100+90+0,被卡常+写错文件名。A可以发现一个简单的dp,也就是设\(f_{l,r}\)为删光\([l,r]\)的答案,那么显然有:\[f_{l,r}=\min(\max(f_{l+1,r-1},w_{l,r}),\min_k\max(f_{l,k},f_{r,k}))\]现在是\(O(n^3)\)的,我们需要优化。我们发现,这支持二分答......
  • 『联合省选2025集训』『省选模拟赛1』 Day5 总结
    前言落日沉溺于橘色的海,晚风沦陷于赤诚的爱。省流:省选集训,\(\texttt{BZ13}\)人,\(50+20+0=70\),\(\texttt{rk11}\),因为有两个跟我并列倒一,真的糖丸了,低年级的也考不过。T1不会用\(\text{Bitset}\)查询最低位的\(1\),即便不会,\(\mathcal{O}(\frac{n^3\times\log(n^2)}{\o......
  • 省选训练赛 #11 记录
    个人认为B和C质量都很高。B一个数轴上有\(n\)个炸弹,第\(i\)个炸弹位于\(X_i\),爆炸半径为\(R_i\),权值为\(v_i\),这些炸弹的排布有两个性质:若炸弹\(x\)可以直接或间接引爆炸弹\(y\),那么\(y\)一定不能直接或间接引爆炸弹\(x\)。定义炸弹序列\(a_1,a_2,\do......
  • 省选集训杂题乱写
    碎碎念不去做专题做这个是吧?......
  • 『联合省选2025集训』『图的连通性进阶』Day3 略解
    前言我们趋行在人生这个亘古的旅途,在坎河中奔跑,在挫折里涅槃,忧愁缠满全身,痛苦飘洒一地。我们累,却无从止歇;我们苦,却无法回避。今天是连通性的进阶题目,重点是耳分解,双极定向,以及边三连通分量。因为调题速度过慢,导致被硬控,所以第二天晚上补的差不多了再来写的。感觉知识点方面......
  • 「省选联考 2023」人员调度
    离独立想出正解只差一步了。我的做法是使用网络流武器,抛弃了贪心的思考。虽然没有锻炼到贪心能力,但是加深了对网络流的理解吧。考虑撤销可以用线段树分治,故只考虑加入的情况。我们发现这个模型很像费用流,于是考虑建模。源点向所有员工连边,容量为\(1\),费用为其能力值。所......
  • 2024冬季省选层集训总结-索引
    2024集训D1总结-youlv-博客园数学,计数.2024集训D2总结-youlv-博客园贪心,构造,博弈2024集训D3总结-youlv-博客园模拟赛(贪心,博弈,构造)2024集训D4总结-youlv-博客园模拟赛(博弈,树,分治,分块)2024集训D5总结-youlv-博客园数据......