• NOIP模拟测试26「嚎叫响彻在贪婪的机房·主仆见证了 Hobo 的离别·征途堆积出友情的永恒」


    题目比较神仙,注意是题目神仙

    贪婪暗示贪心,堆积暗示堆优化$\%\%\%\%\%\%\%$

    两个乱搞$+$一个堆优化$dp$

    嚎叫响彻在贪婪的机房

    题解

    对于一个序列来说只要他们差的$gcd$不为$1$就可以构成等差数列

    例如

    $2$    $4$     $16$

    $2$与$4$差$2$ $4$与$16$差$12$ 

    $gcd(2,12)!=1$故构成等差序列

    那么我们维护公差,然后每次的差和当前公差比较,若$gcd==1$则等差数列从这里断开,否则将公差置成$gcd$

    举个例子

    $2$     $8$    $14$      $16$     $18$      $20$

    $2$     $8$    $14$构成公差为$6$等差数列,之后$16$     $18$      $20$构成公差为$2$等差序列

    显然我们可以让他们合并为公差为$2$等差序列

    注意判重,判差为$1$,

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define A 1111111
    ll read(){
        ll x=0,f=1;char c=getchar();
        while(!isdigit(c)){
            if(c=='-') f=-1;
            c=getchar();
        }
        while(isdigit(c)){
            x=x*10+c-'0';
            c=getchar();
        }
        return x*f;
    }
    set<ll> st;
    set<ll> ::iterator it;
    ll n,m,d=0,ans=0;
    ll a[A];
    void  cl(ll x){
        st.clear();
        d=0;
        ans++;
        st.insert(a[x]);
    }
    ll gcd(ll x,ll y){
        if(y==0) return x;
        return gcd(y,x%y);
    }
    int main(){
        n=read();
        for(ll i=1;i<=n;i++){
            a[i]=read();
        }
        cl(1);
        for(ll i=2;i<=n;i++){
            if((it=st.find(a[i]))!=st.end()) {
    //        printf("i=-%lld
    ",i);
                cl(i);
                continue;
            }
            if(abs(a[i]-a[i-1])==1||a[i]==a[i-1]){
                cl(i);
                continue;
            }
    //        printf("d=%lld
    ",d);
            if(d==0){
                st.insert(a[i]);
                d=abs(a[i]-a[i-1]);
            }
            else {
                ll g=gcd(d,abs(a[i]-a[i-1]));
    //            printf("g=%lld d=%lld abs=%lld
    ",g,d,abs(a[i]-a[i-1]));
                if(g==1||g==0){
                    cl(i);
                }
                else {
                    st.insert(a[i]);
                    d=g;
                }
            }
        }
        printf("%lld
    ",ans);
    }
    View Code

    主仆见证了 Hobo 的离别

    题解

    建边,建立包含关系的树,例如$1,2$交集为$3$那么$1$包含$3$,$2$包含$3$

    再例如$1,2$并集为$3$那么$3$包含$1$,$3$包含$2$

    询问$x$,$y$所属关系就从$y$开始$dfs$若找到$x$即符合

    暴力就是正解

    让我们分析一下复杂度

    题目中说

    新元件的编号等于融合之前元件的总个数加一。当然,参与融合的 K个元件融合之后依然存在,并且每个元件至多参与一次融合

    数据范围

    极限情况下肯定就是分开连边

    那么$250000$个分开连边,产生$125000$,然后下一层产生$62500$再下一层.....

    显然是$log$的最终是$18$层

    而且我们建出来树是下图这样的从一点往下搜

    所以极限复杂度$18*250000$可过

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define A 1111111
    ll read(){
        ll x=0,f=1;char c=getchar();
        while(!isdigit(c)){
            if(c=='-') f=-1;
            c=getchar();
        }
        while(isdigit(c)){
            x=x*10+c-'0';
            c=getchar();
        }
        return x*f;
    }
    ll n,m,cnt,ok,tot=0;
    ll some[A],fa[A],nxt[A],ver[A],head[A];
    ll find(ll x){
        if(fa[x]!=x){
            fa[x]=find(fa[x]);
        }
        return fa[x];
    }
    void haha(){
        for(ll i=1;i<=500000;i++){
            fa[i]=i;
        }
    }
    void merge(ll x,ll y){
        x=find(x),y=find(y);
        if(x!=y) fa[x]=y;
    }
    void add(ll x,ll y){
    //    printf("x=%lld y=%lld
    ",x,y);
        nxt[++tot]=head[x],head[x]=tot,ver[tot]=y;
    }
    void dfs(ll x,ll pre,ll ineed){
        if(x==ineed) ok=1;
        if(ok) return ;
        for(ll i=head[x];i;i=nxt[i]){
            ll y=ver[i];
            if(y==pre) continue;
            dfs(y,x,ineed);
        }
    }
    /*ll ithave[A],beihave[A];
    ll getithave(ll x){
        if(ithave[x]!=x){
            ithave[x]=getithave(ithave[x]);
        }
        return ithave[x];
    }
    void mergeit(ll x,ll y){
        x=getithave(x);
        y=getithave(y);
        if(ithave[x]!=ithave[y]){
            ithave[x]=y;
        }
    }
    ll getbeihave(ll x){
        if(beihave[x]!=x){
            beihave[x]=getbeihave(beihave[x]);
        }
        return beihave[x];
    }
    void mergebei(ll x,ll y){
        x=getbeihave(x);
        y=getbeihave(y);
        if(beihave[x]!=beihave[y]){
            beihave[x]=y;
        }
    }*/
    int main(){
        n=read(),m=read();
        cnt=n;
        for(ll i=1,opt,ques,k,QwQ;i<=m;i++){
            ques=read();
            if(ques==0){
                opt=read(),k=read();
                cnt++;
                if(opt==1){
                    for(ll j=1;j<=k;j++){
                        QwQ=read();
                        //1属于2 1--->2
                        add(cnt,QwQ);
                        if(k==1)
                            add(QwQ,cnt);
                    }
                }
                else {
                    for(ll j=1;j<=k;j++){
                        QwQ=read();
                        add(QwQ,cnt);
                        if(k==1)
                            add(cnt,QwQ);
                    }
                }
            }
            else{
                ok=0;
                ques=read(),QwQ=read();
                dfs(QwQ,0,ques);
                printf("%lld
    ",ok);
            }
        }
    }
    View Code

    征途堆积出友情的永恒

    题解

     首先普通dp应该都会吧

    $f[i]=min(f[j]+max(sum[i]-sum[j],b[j]))$

        for(ll i=1;i<=n;i++){
            for(ll j=max(i-k,0ll);j<=i-1;j++){
                ll fee=max(sum[i]-sum[j],a[j]);
                f[i]=min(f[j]+fee,f[i]);
            }
        }
    一言不和上代码

    怎么优化,

    线段树或者堆

    思考sum[i]变化很烦,线段树很难维护(然而Mr_zkt维护出来了$%%%$)我没打线段树

    用堆维护我们需要寻找不变量显然$f[j]+b[j]$和$f[j]-sum[j]$是不变量

    开两个小根堆,一个维护$min(f[j]+b[j])$一个维护$f[j]-sum[j]$

    转移时$min(q1.top(),q2.top+sum[i])$

    细节稍多

    • $STL$的各种$empty$往上仍,
    • 判断是否可以转移(<=k)限制
    • 在$f[j]+b[j]$$<$$f[j]-sum[j]+sum[i]$时第一个堆不合法,第一个堆扔到第二个堆

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define A 1010101
    ll f[A],a[A],sum[A],b[A];
    ll n,k,minn;
    struct node{
        ll id,val;
        friend bool operator < (const node &a,const node &b){
            return a.val>b.val;
        }
    };
    priority_queue<node> q1,q2;
    //q1用来存f+b q2存 f-s
    ll read(){
        ll x=0,f=1;char c=getchar();
        while(!isdigit(c)){
            if(c=='-') f=-1;
            c=getchar();
        }
        while(isdigit(c)){
            x=x*10+(c-'0');
            c=getchar();
        }
        return f*x;
    }
    void work(){
        memset(f,0x3f,sizeof(f));
        f[0]=0;
        node o;
        o.id=0,o.val=b[0];
        q1.push(o);
        for(ll i=1;i<=n;i++){
            node x1,x2;
            while(!q1.empty()){
                x1=q1.top();
                if(x1.id>=i-k) break;
                q1.pop();
            }
            while(!q2.empty()){
                x2=q2.top();
                if(x2.id>=i-k) break;
                q2.pop();
            }
            while(!q1.empty()){
                x1=q1.top();
                if(x1.val>=f[x1.id]-sum[x1.id]+sum[i]) break;
    //            printf("feifa
    ");
    //            printf("x1.val=%lld id=%lld f-s=%lld
    ",x1.val,x1.id,f[x1.id]-sum[x1.id]+sum[i]);
                q1.pop();
                node x3;
                x3.id=x1.id,x3.val=f[x1.id]-sum[x1.id];
                q2.push(x3);
            }
            while(!q1.empty()){
                x1=q1.top();
                if(x1.id>=i-k) break;
                q1.pop();
            }
            while(!q2.empty()){
                x2=q2.top();
                if(x2.id>=i-k) break;
                q2.pop();
            }
    //        printf("q1.top id=%lld val=%lld 2=%lld %lld
    ",x1.id,x1.val,x2.id,x2.val);
            //f[i]=min(x1.val,x2.val+sum[i]);
            if(!q1.empty())f[i]=min(0x7ffffffffff,q1.top().val);
            if(!q2.empty())f[i]=min(0x7ffffffffff,q2.top().val+sum[i]);
    //        printf("f[%lld]=%lld
    ",i,f[i]);
            x1.id=i,x1.val=f[i]+b[i];
            q1.push(x1);
        }
    }
    int main(){
        n=read(),k=read();
        for(ll i=1;i<=n;i++){
            sum[i]=read();
            sum[i]+=sum[i-1];
        }
        for(ll i=0;i<n;i++){
            b[i]=read();
        }
        work();
        printf("%lld
    ",f[n]);
    }
    View Code
  • 相关阅读:
    第一篇博客
    Word2vec负采样
    Ubuntu系统为应用建立桌面快捷方式(以Pycharm为例)
    Kaggle入门Titanic——模型建立
    Kaggle入门Titanic——特征工程
    ubuntu系统theano和keras的安装
    win7系统下python安装numpy,matplotlib,scipy和scikit-learn
    ubuntu14.04环境下spyder的安装
    防止IE7,8进入怪异模式
    自定义列表
  • 原文地址:https://www.cnblogs.com/znsbc-13/p/11377871.html
Copyright © 2020-2023  润新知