[NOI2019]序列

序列

题解

非要我评价的话我只能说*b题就这样的,网络流就网络流嘛,还非得手动模拟,就是屑。

首先,我们应该比较容易地构建出它的网络流模型。
至少有 L L L个选择的下标相同显然可以转化成最多选择 K − L K-L KL对下标不同。
我们的网络流相当于构建一个二分图,图上所有 a i a_i ai都可以随便和它对应的 b i b_i bi相匹配,而不同的匹配最多只有 K − L K-L KL个,连出来是长这样的:
在这里插入图片描述
我们要去求的是这个图的最大费用最大流图画得貌似有点丑,显然直接把边权倒过来跑肯定是跑不过 n ⩽ 2 × 1 0 5 n\leqslant 2\times 10^5 n2×105的。
对于这种简单分层图的费用流一种比较经典的方法是利用贪心来模拟网络流。
显然,这种退流也是比较容易整到可撤销贪心上的。
我们先观察这张图,显然,那 K − L K-L KL条边的选择余地是最大的,所以说如果我们还没选满的话就可以直接把 A A A现在剩下的最大的一个和 B B B现在剩下的最大的一个给拿进去。
否则的话我们就有两种选择,一是将一对没有被选择的 ( a i , b i ) (a_i,b_i) (ai,bi)选上,一是撤销原先选上的一堆 ( a i , b j ) (a_i,b_j) (ai,bj),变成 ( a i , b i ) + ( a x , b y ) (a_i,b_i)+(a_x,b_y) (ai,bi)+(ax,by),这样都不会影响我们拿 K − L K-L KL条边的选择。
我们可以直接把两种的改变量记录下来,比较哪种改变量更大就选哪种。

当然,直接维护这些可能不太好搞。
我们可以维护 a a a选在那 K − L K-L KL条边中的集合, b b b选在那 K − L K-L KL条边中的集合, a a a没有被选的集合, b b b没有被选的集合。
显然,一种改变量就是后面两个集合的交集中和最大的那一堆,一种改变量就是把第一个集合中 i i i中最大的 b i b_i bi加上,减去第二个集合中最小的 b i b_i bi,在把后面两个集合中最大的拿出来。
这些都可以直接用优先队列维护。
大体思路就是这样的,不过还得注意一些细节。
比如说我们维护的加入那 K − L K-L KL条边的集合是不能有交集的,否则它们就不会贡献在这里了。
也就是说我们后面加进来的点与它有交集的话,可以直接把它们都删掉。
这当然会导致后面又可以随便选边了,当然要记录一下。
另外就是它可能上面 ( a i , b j ) − > ( a i , b i ) + ( a x , b y ) (a_i,b_j)->(a_i,b_i)+(a_x,b_y) (ai,bj)>(ai,bi)+(ax,by) y y y也是可能为 j j j的,要特判一下。
当然,也可以是 ( a i , b j ) − > ( a j , b j ) + ( a x , b y ) (a_i,b_j)->(a_j,b_j)+(a_x,b_y) (ai,bj)>(aj,bj)+(ax,by)的,对称的嘛。

所以只需要维护堆就行了,每次都会多选一对点,最多只会选 K K K次。
总时间复杂度 O ( ∑ n log ⁡ n ) O\left(\sum n\log n\right) O(nlogn)

源码

维护 7 7 7个堆也可以过。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<LL,int> pii;
#define MAXN 200005
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lowbit(x) (x&-x)
const int mo=998244353;
const int inv2=5e8+4;
const int jzm=2333;
const int zero=15;
const LL INF=0x3f3f3f3f3f3f3f3f;
const double Pi=acos(-1.0);
const double eps=1e-9;
const int lim=1000000;
const int orG=3,ivG=332748118;
const int n1=500;
const int M=MAXN/n1+5,N=n1+5;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
    _T f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
    x*=f;
}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1;}return t;}
int T,n,K,L,a[MAXN],b[MAXN];LL ans;
bool visa[MAXN],visb[MAXN];
priority_queue<pii>A1,B1,A2,B2,A3,B3,C;
int main(){
    read(T);
    while(T--){
        while(!A1.empty())A1.pop();while(!B1.empty())B1.pop();
        while(!A2.empty())A2.pop();while(!B2.empty())B2.pop();
        while(!A3.empty())A3.pop();while(!B3.empty())B3.pop();
        while(!C.empty())C.pop();
        read(n);read(K);read(L);int num=0;
        for(int i=1;i<=n;i++)read(a[i]);
        for(int i=1;i<=n;i++)read(b[i]);
        for(int i=1;i<=n;i++)
            A1.push(mkpr(a[i],i)),
            B1.push(mkpr(b[i],i)),
            C.push(mkpr(a[i]+b[i],i));
        for(int i=1;i<=K;i++){
            while(!A1.empty()&&visa[A1.top().sec])A1.pop();
            while(!B1.empty()&&visb[B1.top().sec])B1.pop();
            while(!A2.empty()&&!visa[A2.top().sec])A2.pop();
            while(!B2.empty()&&!visb[B2.top().sec])B2.pop();
            while(!A3.empty()&&!visa[A3.top().sec])A3.pop();
            while(!B3.empty()&&!visb[B3.top().sec])B3.pop();
            while(!C.empty()&&(visa[C.top().sec]||visb[C.top().sec]))C.pop();
            if(num<K-L){
                pii ta=A1.top(),tb=B1.top();A1.pop();B1.pop();ans+=ta.fir+tb.fir;
                visa[ta.sec]=visb[tb.sec]=1;if(ta.sec==tb.sec)continue;
                if(!visa[tb.sec]&&!visb[ta.sec])num++;
                if(visb[ta.sec]&&visa[tb.sec])num--;
                if(visb[ta.sec])visb[ta.sec]=0;else A2.push(mkpr(b[ta.sec],ta.sec)),A3.push(mkpr(-ta.fir,ta.sec));
                if(visa[tb.sec])visa[tb.sec]=0;else B2.push(mkpr(a[tb.sec],tb.sec)),B3.push(mkpr(-tb.fir,tb.sec));
            }
            else{
                LL tmpa=-INF,tmpb=-INF,tmpc=-INF,tmpd=-INF,tmpe=-INF;
                if(!C.empty())tmpc=C.top().fir;
                if(!A2.empty()&&!B3.empty())tmpa=A2.top().fir+B3.top().fir+A1.top().fir+B1.top().fir;
                if(!A3.empty()&&!B2.empty())tmpb=A3.top().fir+B2.top().fir+A1.top().fir+B1.top().fir;
                if(!A2.empty())tmpd=A2.top().fir+A1.top().fir;
                if(!B2.empty())tmpe=B2.top().fir+B1.top().fir;
                LL td=max(max(tmpa,tmpb),max(tmpc,max(tmpd,tmpe)));ans+=td;
                if(tmpc==td){pii t=C.top();C.pop();visa[t.sec]=visb[t.sec]=1;}
                else if(tmpa==td){
                    pii t1=A2.top(),t2=B3.top();A2.pop();B3.pop();
                    pii ta=A1.top(),tb=B1.top();A1.pop();B1.pop();
                    visa[t1.sec]=visb[t2.sec]=0;visb[t1.sec]=1;B1.push(mkpr(b[t2.sec],t2.sec));
                    if(!visa[t2.sec])C.push(mkpr(a[t2.sec]+b[t2.sec],t2.sec));visa[ta.sec]=visb[tb.sec]=1;
                    if(visb[ta.sec])visb[ta.sec]=0,num--;else A2.push(mkpr(b[ta.sec],ta.sec)),A3.push(mkpr(-ta.fir,ta.sec));
                    if(visa[tb.sec])visa[tb.sec]=0,num--;else B2.push(mkpr(a[tb.sec],tb.sec)),B3.push(mkpr(-tb.fir,tb.sec));
                }
                else if(tmpb==td){
                    pii t1=A3.top(),t2=B2.top();A3.pop();B2.pop();
                    pii ta=A1.top(),tb=B1.top();A1.pop();B1.pop();
                    visa[t1.sec]=visb[t2.sec]=0;visa[t2.sec]=1;A1.push(mkpr(a[t1.sec],t1.sec));
                    if(!visb[t1.sec])C.push(mkpr(a[t1.sec]+b[t1.sec],t1.sec));visa[ta.sec]=visb[tb.sec]=1;
                    if(visb[ta.sec])visb[ta.sec]=0,num--;else A2.push(mkpr(b[ta.sec],ta.sec)),A3.push(mkpr(-ta.fir,ta.sec));
                    if(visa[tb.sec])visa[tb.sec]=0,num--;else B2.push(mkpr(a[tb.sec],tb.sec)),B3.push(mkpr(-tb.fir,tb.sec));
                }
                else if(tmpd==td){
                    pii t1=A2.top(),t2=A1.top();A2.pop();A1.pop();
                    visa[t1.sec]=0;visb[t1.sec]=visa[t2.sec]=1;
                    if(visb[t2.sec])visb[t2.sec]=0,num--;
                    else A2.push(mkpr(b[t2.sec],t2.sec)),A3.push(mkpr(-t2.fir,t2.sec));
                }
                else if(tmpe==td){
                    pii t1=B2.top(),t2=B1.top();B2.pop();B1.pop();
                    visb[t1.sec]=0;visa[t1.sec]=visb[t2.sec]=1;
                    if(visa[t2.sec])visa[t2.sec]=0,num--;
                    else B2.push(mkpr(a[t2.sec],t2.sec)),B3.push(mkpr(-t2.fir,t2.sec));
                }
            }
        }
        printf("%lld\n",ans);ans=0;
        for(int i=1;i<=n;i++)visa[i]=visb[i]=0;
    }
    return 0;
}

谢谢!!!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
IOI国家集训队2019论文集,目录: 钟子谦 - 《两类递推数列的性质和应用》 王修涵 - 《浅谈图模型上的随机游走问题》 杨骏昭 - 《“小水题”命题报告》 高嘉煊 - 《浅谈图的点着色问题》 戴 言 - 《浅谈格路计数相关问题》 李佳衡 - 《算法竞赛中一些数论问题的推广与高斯整数初探》 范致远 - 《“基础圆方树练习题”命题报告》 徐翊轩 - 《“整点计数”命题报告以及对高斯整数的若干研究》 张哲宇 - 《浅谈树上分治算法》 吴思扬 - 《“组合数求和”命题报告》 王思齐 - 《浅谈一类简洁数据结构》 陈孙立 - 《子串周期查询问题的相关算法及其应用》 吴作同 两关递推数列的性质和应用 福州第中学钟了谦 两类递推数列的性厉和应用 福州第三中学钟子谦 摘要 线性递推数列和整式递搾数列是数学中常见的两类递推数列,本文介绍了这两类递推 数列的定义、性质和有关算法,并展示了它们在信息学竞赛中的一些应用。 前言 线性递推数列被引入算法竞赛界凵经有至少互年,但是直没有得到特别广泛的普及 整式递推数列是线性递推数列的一个自然的拓展,近两年才被引入信息学竞赛。本文希望 能够系统介绍这两类数列的性质和在信息学竞赛中的用途,使读者在思考有关问题时有迹 可循 本文首先在第1节介绍了线性递推数列,接下来在第2节介绍了整式递推数列。对于 这两类数列,本文介绍了它们的定义、性质、有关算法和实际例题,对于线性递推数列本文 还介绍了些与线性代数相关的应用。 1线性递推数列 1.1定义 定义1.1.我们称长度有限的数列为有限数列,长度无限的数列为无限数列。 定义1.2.我们称形式幂级教F最高次项的次数为形式幂级数F的次数,记为deg(F) (可能为α)。特别地,我们定义零多项式的次数为负无穷大(-0)。 定义13.对于有限数列{a0,a1,a2…an-1},我们定义它的生成函数为多项式A(x) ∑=ax。对于无限数列{ao,a1,a2…},我们类似地定义它的生成函数为形式幂级数A(x) 定义1.4.对于无限效列{0,a1,u2…}和有限非空数列{ro,r1,r2…rm-n},若对于任意 卩≥m-1,有∑ank=0,则称数列r为数列a的线性递归式。若ro=1,我们称数 列r为数列a的线性递推式。我们称存在线性递推式的无限数列为线性递推数列 两关递推数列的性质和应用 福州第中学钟了谦 对于有限数列{a0,a1,a2…an-l和有限非空教列{ro,r1,r2…rm-1},类似地,若对于任 意m-1≤卩≤n-1,有∑四=an-k-0,则称数列r为数列a的线性递归式。若10-1 我们称数列r为数列a的线性递推式。 我们称这个线性递推式的阶数为它的长度减一,称数列a阶数最小的线性递推式为数 列a的最短线性递推式。 12基本性质和判定方法 在生成函数的观点下看线性递归式,我们有如下结论 定理11.对于无限数列{a,a1,a2…}和有限非空数列{ro,n1,r2…rm-1},设数列a和数列 r所对应的生成函数为A和R,数列r为数列a的线性递归式等价于存在次数不超过m-2 的多项式S满足AR+S=0。 对于有限数列{a0,a1,a2…an-1}和有限数列{r,r1,r2…Fm-1},设数列a和数列r所对 应的生成函数为A和R,数列厂为数列a的线性递归式等价于存在次数不超过m-2的多 项式S满足AR+S≡0(modx)。 证明.下面证明无限数列的情况,有限数列的情况也是类似的 对于k≥m-1,考察两侧x次项的系数,我们有[x(x)R(x)=∑mbra-=0。只 需要取适当的S使得低次项系数为0即可 接下来我们介绍儿种常见的判定线性递推数列的方法。 推论1.1.对于无限数列{a,a1,a2∵},设数列a所对应的生成函数为A,a为线性递推 数列当且仅当存在常敖项为1的多项式R和多项式S满足A=是。数列a的最短线性递 推式阶数就是对于这样的R和S,max(deg(R),deg(S)+1)的最小可能值。 证明.由定理1.1移项即得 定理1.2.对于一个nXn的矩阵M,无限数列{,M,M2,M3…)是一个线性递推数列,它 的最短线性递推式阶数不超过n 证明.考虑矩阵M的特征多项式p,它满足deg(p)=n,xlp(x)=1。 I Cayley-Hamilton 定理,我们有p(M)=0。该定理的证明可参见参考文献2],由于和本文主题关系不大,这 里略厶。 设p(x)=∑=0Cnx,P(M)=0即∑:0Cm-M=0,两边乘M得∑=0CnM+!=0 即∑0c;M件+=0。所以{c,C1…cn}即为

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值