zoukankan      html  css  js  c++  java
  • QZS8.19

    T1

    过不了大样例

    查不出错。。。可能想错了

    wawawa爆零了

    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int N=500005;
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    inline void Min(int &x,int y) {if(x>y)x=y;}
    inline void Max(int &x,int y) {if(x<y)x=y;}
    int jue(int x,int y) {return x>y?x-y:y-x;}
    vector<int>v[N];
    int n,k,fa[N],ban[N];
    int to[N],nxt[N],hd[N],w[N],tot;
    inline void add(int x,int y,int z) {
        to[++tot]=y;w[tot]=z;nxt[tot]=hd[x];hd[x]=tot;
    }
    
    int dep[N],dis[N],mxdep;
    int mi[N];
    void dfs(int x) {
        for(int i=hd[x];i;i=nxt[i]) {
            int y=to[i];
            if(y==fa[x]) continue;
            dep[y]=dep[x]+1;
            v[dep[y]].push_back(y);
            Max(mxdep,dep[y]);
            dis[y]=dis[x]+w[i];
            Min(mi[dep[y]],dis[y]);
            dfs(y);
        }
    }   
    int main() {
        memset(mi,0x3f,sizeof(mi));
        n=read();k=read();
        for(int i=2,z;i<=n;i++) {
            fa[i]=read();z=read();ban[i]=read();
            add(fa[i],i,z);
        }   
        dep[1]=0;mi[0]=0;
        v[0].push_back(0);
        dfs(1);
        puts("0");
        for(int s=1;s<=mxdep;s++) {
            for(int j=0;j<v[s].size();j++) {
                if(!ban[v[s][j]]) 
                    for(int last=0;last<=mxdep;last++) 
                        Min(dis[v[s][j]],mi[last]+jue(s,last)*k);
                Min(mi[s],dis[v[s][j]]);
            } 
        }
        for(int i=2;i<=n;i++) 
            printf("%d
    ",dis[i]);
        return 0;
    }
    

    不知所错。。。

    去撸正解吧


    额怎么说呢。。。想的又和正解挺像的

    就是每层开vector 存一个当前层最小值

    有一个点没有想到

    就是可以记录一个bestpos最优点,它后面的层都可以用它更新,正确性证明(口糊):

    我们按层数从小到大推,设之前的bestpos为 i ,新的bestpos为 j (i到1的距离>j到1的距离) ,那么对后面的层 k 来说 dep[k]-dep[i] > dep[k]-dep[j] && i到1的距离>j到1的距离 ∴ 之后跳 j 一定比跳 i 优

    还有个小优化 输入边权的时候如果能坐车就和k取min

    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int N=500005;
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    inline void Min(int &x,int y) {if(x>y)x=y;}
    inline void Max(int &x,int y) {if(x<y)x=y;}
    vector <int> v[N];
    int n,k,fa[N],ban[N];
    int to[N],nxt[N],hd[N],w[N],tot;
    inline void add(int x,int y,int z) {
        to[++tot]=y;w[tot]=z;nxt[tot]=hd[x];hd[x]=tot;
    }
    
    int dep[N],dis[N],mxdep;
    int best[N],bestpos;
    int get(int x,int y) {return best[x]+(y-x)*k;}
    int main() {
        memset(best,0x3f,sizeof(best));//每一层的最小值
        n=read();k=read();
        for(int i=2,z;i<=n;i++) {
            fa[i]=read();z=read();ban[i]=read();
            dep[i]=dep[fa[i]]+1;
            Max(mxdep,dep[i]);
            if(!ban[i]) Min(z,k);//优化
            add(fa[i],i,z);
        }   
        for(int i=1;i<=n;i++) v[dep[i]].push_back(i); 
        for(int i=0;i<=mxdep;i++) {//这个循环是第i层已经完成,在第i层推向第i+1层
            for(int j=0;j<v[i].size();j++) {
                int y=v[i][j];
                Min(best[dep[y]],dis[y]);
            }
            int mi=best[i];
            for(int j=0;j<v[i].size();j++)
                if(!ban[v[i][j]])
                    Min(dis[v[i][j]],mi);
            if(i&&get(bestpos,i)>get(i,i)) bestpos=i;
            for(int j=0;j<v[i].size();j++) {
                int x=v[i][j];
                for(int s=hd[x];s;s=nxt[s]) {
                    int y=to[s];
                    dis[y]=dis[x]+w[s];
                    if(!ban[y]) Min(dis[y],get(bestpos,i+1));
                }
            }
        }
        for(int i=1;i<=n;i++) 
            printf("%d
    ",dis[i]);
        return 0;
    }
    /*
    4 3
    1 7 1
    1 5 0
    2 1 0
    */
    

    T2

    Solution

    把原来的pos排序,二分时间 t ,然后更新成新的pos’ ,再排序比较二者顺序是否完全相同。

    疑难:对k不会处理 60 pts

    std: 其实就差一点想到正解。。。我们对新的pos’ 求出最长上升子序列LIS , 然后 若序列长度>=n-k 就可行

    (n^2暴力枚举任意两个点相撞时间,取min可以90分。。。痛心)


    60分

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N=50005;
    int n,k;
    double ans;
    struct node{
         double p,v;int id,rk;
    }a[N],b[N];
    bool cmp(node a,node b) {
        return a.p==b.p?a.id<b.id:a.p<b.p;
    }
    bool check(double t) {
        for(int i=1;i<=n;i++) {
            b[i]=a[i];
            b[i].p=a[i].p+a[i].v*t;
        }
        sort(b+1,b+1+n,cmp);
        for(int i=1;i<=n;i++)
            if(b[i].rk!=i) return 0;
        return 1;
    }
    int main() {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++) {
            scanf("%lf%lf",&a[i].p,&a[i].v);
            a[i].id=i;
        }
        sort(a+1,a+1+n,cmp);
        for(int i=1;i<=n;i++)
            a[i].rk=i;
        
        double l=0,r=1000000;
        while(l<=r) {
            double mid=(l+r)/2.0;
            if(check(mid)) ans=mid,l=mid+0.00001;
            else r=mid-0.00001;
        }       
        if(ans>=999999) puts("Forever");
        else printf("%.4lf",ans);
        return 0;
    }
    
    

    100分

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long double ld;
    const int N=1e5+5;
    const ld eps=1e-4;
    const ld inf=1e12;
    int n,k;
    struct node{
        ld p,v;
        int id;
        bool operator < (const node &x) const {
            return p<x.p;
        }
    }a[N],b[N];
    inline void Max(int &x,int y) {if(x<y)x=y;}
    int c[N];
    int query(int x) {
        int res=0;
        for(int i=x;i;i-=i&(-i))
            Max(res,c[i]);
        return res;
    }
    void upd(int x,int v) {
        for(int i=x;i<=n;i+=i&(-i))
            Max(c[i],v);   
    }
    inline bool check(ld t) {
        memset(c,0,sizeof(c));
        for(int i=1;i<=n;++i)
            b[i].p=a[i].p+a[i].v*t,b[i].id=i;
        sort(b+1,b+n+1);
        for(int i=1;i<=n;++i)
            a[b[i].id].id=i;
        for(int i=1;i<=n;++i) {
            int x=a[i].id;
            int y=query(x-1);
            upd(x,y+1);
        }
        return query(n)>=n-k;
    }
    int main() {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;++i)
            scanf("%Lf%Lf",&a[i].p,&a[i].v);
        sort(a+1,a+n+1);
        ld l=0,r=inf,mid;
        while(abs(l-r)>eps*eps){
            mid=(l+r)/2;
            if(check(mid)) l=mid;
            else r=mid;
        }
        if(abs(mid-inf)<=eps) puts("Forever");
        else printf("%.4Lf",mid);
        return 0;
    }
    
    
    

    T3

    不会处理n>1

    好像斜率优化啊


    首先,一个结论是,对于长度为 len 的一段,切 k 次,代价最小的切法是尽量平均地切,也就是我们要切出长度为 len/k的段一共 k-x mod k 段,长度为 len/k+1的段一共 x mod k 段

    令 cost(len,k) 为长度为len,切k刀的最小代价。

    注意到其差分序列是不降的——意思解释你越往下切,代价减少的越慢。

    栗子:
    cost(8,0) = 64
    cost(8,1) = 32 降32
    cost(8,3) = 16 降16
    

    image-20200822172117845

    问题可以形象的转化为上图,每个格子值为代价差 (cost(len,k+1)-cost(len,k))

    每一列是一个饼,每一行的值都小于0,且从上到下绝对值递减

    多切1刀的话就取堆顶。问题转化成找一条包含k个格子的轮廓线。

    总体复杂度O(qnlog)的,45分

    对于每个询问有的只是k+1,k-1,你要是再重新求一遍显然不划算。

    但堆只允许我们往下拓展取格子,不能还原回去

    由于要支持删除,我们用 (multiset) 而不用堆

    考虑如何反悔:
    我们维护两个 (multiset) ,一个维护切,一个维护反悔
    两个 (multiset) 按照差从小到大(因为是负数)自动排序
    (k) 增加的时候,取切的顶加,同时由于 (k) 增加了,原来的 (k) 的时候对应的反悔就失效了,于是删除那个反悔,以及原来的切,同时加入新的切和反悔
    (k) 减小的时候取反悔的顶加,同时旧的切和反悔失效,删掉,加入新的切和反悔

    对于加入每一个元素,初始放入 (multiset) 时,在切的set里放入 (cost(len,2)-cost(len,1)) ,在反悔里放入 (cost(len,0)-cost(len,1))
    记录每一个元素已经被分为几段,初始时为1

    对于加入新的饼也是类似的,但如果你发现你反悔后再加入的不是新的饼的贡献,说明这加的新饼没用

    #include <iostream>
    #include <cstdio>
    #include <set>
    using namespace std;
    #define int long long 
    const int inf=8e18; 
    const int N=1000005; 
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    int n,q,k,a[N],d[N],ans;//d[i]表示i号pancake切了几刀
    int get(int x,int k) {
        if(k==0||x<k) return inf;
        int len=x/k;
        return len*len*(k-x%k)+(len+1)*(len+1)*(x%k);
    }
    struct node{
        int pos,val;
        node(int a,int b):pos(a),val(b){}
        bool operator < (const node &x) const {
            return val==x.val?pos<x.pos:val<x.val;
        }
    };
    multiset<node>s0,s1;
    void add() {
        multiset<node>::iterator it=s0.begin();
        ans+=it->val;
        s1.erase(node(it->pos,get(a[it->pos],d[it->pos]-1)-get(a[it->pos],d[it->pos])));
        s0.erase(*it);
        ++d[it->pos];
        s0.insert(node(it->pos,get(a[it->pos],d[it->pos]+1)-get(a[it->pos],d[it->pos])));
        s1.insert(node(it->pos,get(a[it->pos],d[it->pos]-1)-get(a[it->pos],d[it->pos])));
    }
    void del() {
        multiset<node>::iterator it=s1.begin();
        ans+=it->val;
        s0.erase(node(it->pos,get(a[it->pos],d[it->pos]+1)-get(a[it->pos],d[it->pos])));
        s1.erase(*it);
        --d[it->pos];
        s0.insert(node(it->pos,get(a[it->pos],d[it->pos]+1)-get(a[it->pos],d[it->pos])));
        s1.insert(node(it->pos,get(a[it->pos],d[it->pos]-1)-get(a[it->pos],d[it->pos])));
    }
    signed main() {
        n=read();q=read();k=read();
        for(int i=1;i<=n;i++) {
            a[i]=read();
            ans+=a[i]*a[i];
            d[i]=1;
            s0.insert(node(i,get(a[i],2)-get(a[i],1)));
            s0.insert(node(i,get(a[i],0)-get(a[i],1)));
        }
        for(int i=1;i<=k;i++)
            add();
        printf("%lld
    ",ans);
        for(int i=1,op;i<=q;i++) {
            op=read();
            if(op==1) add();
            else if(op==2) del();
            else {
                n++;
                a[n]=read();
                d[n]=1;
                ans+=a[n]*a[n];
                s0.insert(node(n,get(a[n],2)-get(a[n],1)));
                s1.insert(node(n,get(a[n],0)-get(a[n],1)));
                int last=ans;
                while(1) {
                    del();
                    add();
                    if(last==ans) break;
                    last=ans;
                }
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    /*
    1 3 1
    4 
    1 
    3 4
    2
    */
    
  • 相关阅读:
    Node.js中流程控制
    设计模式六大原则(转)
    Python中装饰器(转)
    cocos2d-js反射
    With as
    Python中sort与sorted函数
    cocos+kbe问题记录
    Python字符串
    vue判断Object对象是否包含每个键
    vue跳转其他页面并传参
  • 原文地址:https://www.cnblogs.com/ke-xin/p/13546737.html
Copyright © 2011-2022 走看看