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

    etimate

    T1 50

    T2 60

    T3 10

    reality

    T1 20

    T2 90

    T3 10

    T1

    思路:

    我们不妨令所有数先上取整,然后尝试让一些数下取整。显然整数下取整还是原数,所以尽量让小数先下取整。

    假设小数足够多,那么什么时候停止下取整呢,也就是什么时候得到最优解呢?

    上取整 下取整完后的和和原来的和的差的绝对值小于 0.5

    为什么呢?总有方案达成上述情况

    这是其中一种情况

    另一种情况:小数不够多,那么先下取整小数,然后已经得到最优解

    还有一种情况:小数够多,但是要想达到最优解状态下取整的小数个数可能超过区间长度的一半

    实现:

    情况1:

    设上取整和为 sup ,原来的和为 sum,那么需要删除 sup-sum+0.5 个数

    情况2:

    sup 减去小数个数

    情况3:

    sum减去区间长度的一半

    注意:

    我们要下取整的数 数量为区间长的一半,我们确定了下取整的数的小数个数之后,要下取整的整数个数也就确定了。但是如果要下取整的整数个数小于区间总共整数的个数,那么还是要下取整小数

    对于区间问题前缀和就好了

    细节大爆炸

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int N=5e5+10;
    int m,q,cnt[N];
    double a[N],sum[N],sup[N];
    int main() {
        scanf("%d%d",&m,&q);
        for(int i=1;i<=m;i++) {
            scanf("%lf",&a[i]);
            sum[i]=sum[i-1]+a[i];
            sup[i]=sup[i-1]+ceil(a[i]);
            cnt[i]=cnt[i-1]+(floor(a[i])!=ceil(a[i]));//小数数量
        }
        for(int i=1,l,r;i<=q;i++) {
            scanf("%d%d",&l,&r);
            int len=(r-l+1)/2;
            int xs=cnt[r]-cnt[l-1];
            double presum=sum[r]-sum[l-1];
            double up=sup[r]-sup[l-1];
            if(min(len,xs)<=(int)(up-presum)) up-=min(len,xs);//2
            else {
                int v=min(min(len,xs),(int)(up-presum+0.5));//下取整的小数
                up-=v;
                int t=len-v;//区间剩下的数
                if(2*len-xs<t) up-=(t-(2*len-xs));
            }
            printf("%.3lf
    ",abs(up-presum));
        }
        return 0;
    } 
    

    T2

    先讲讲我90分的感人暴力。。。

    首先求两点距离树剖lca 就行 dis[x]+dis[y]-2*dis[lca(x,y)] ,由于边权为1,所以不需要开dis数组,用dep就行

    1、对于30%的数据,有N ≤ 1000,M ≤ 1000

    我们枚举[1,n]每个点,判断是否满足m个限制条件,不满足及时break,复杂度O(nmlogn) ——实际上远远不到,所以能骗90

    2、对于另外10%的数据,有Di = 2 × 10^6 ,一共n=10^5个点,所以最远也到不了Di,这显然随便输出一个点就行。

    3、对于另外10%的数据,树是一条链

    判断链就判top是不是都相同就行

    树上差分——看图理解

    对于例子里的2,5,4 ——设2,5距离为dis=dep[5]-dep[2]

    到2和5的距离之和为4 的点 深度范围 [ dep[2]-(d[i]-dis)/2 , dep[5]+(d[i]-dis)/2 ],

    就在 dep[2]-(d[i]-dis)/2的fa -1 ,在 dep[5]+(d[i]-dis)/2 +1

    然后dfs一遍统计答案就行

    O(n+m)左右的

    4、对于另外10%的数据,有Di = Dist(Ai, Bi).

    这也是差分,在a[i] 处 +1 ,在b[i] 处 +1 , 在lca(a[i],b[i])及其fa 处 -1

    #include <cstdio>
    #include <iostream>
    using namespace std;
    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;
    }
    const int N=200005;
    bool flag1=1,flag2=1,flag3=1;
    int n,m,w[N];
    int to[N],nxt[N],hd[N],tot;
    inline void add(int x,int y){
    	to[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;
    }
    
    int siz[N],dep[N],fa[N],son[N];
    void dfs_son(int x,int f){
        siz[x]=1;fa[x]=f;dep[x]=dep[f]+1;
        for(int i=hd[x];i;i=nxt[i]){
            int y=to[i];
            if(y==f) continue;
            dfs_son(y,x);
            siz[x]+=siz[y];
            if(siz[y]>siz[son[x]]) son[x]=y;
        }
    }
    int top[N];
    void dfs_chain(int x,int tp){
        top[x]=tp;
        if(son[x]) dfs_chain(son[x],tp);
        for(int i=hd[x];i;i=nxt[i]){
            int y=to[i];
            if(y==fa[x]||y==son[x]) continue;
            dfs_chain(y,y);
        }
    }
    int LCA(int x,int y) {
        while(top[x]!=top[y]) {
            if(dep[top[x]]<dep[top[y]]) swap(x,y);
            x=fa[top[x]];
        }
        return dep[x]<dep[y]?x:y;
    }
    int a[N],b[N],d[N],rev[N];
    int get_dis(int x,int y) {
        return dep[x]+dep[y]-dep[LCA(x,y)]*2;
    }
    void get_ans(int x) {
        for(int i=hd[x];i;i=nxt[i]){
            int y=to[i];
            if(y==fa[x]) continue;
            get_ans(y);
            w[x]+=w[y];
        }    
    }
    int main() {
        n=read();m=read();
        for(int i=1,x,y;i<n;i++) {
            x=read();y=read(); 
            add(x,y);add(y,x);
        }
        dfs_son(1,0);dfs_chain(1,1);
        for(int i=1;i<n;i++)
            if(top[i]!=top[i+1]) flag2=0;
        for(int i=1;i<=m;i++) {
            a[i]=read();b[i]=read();d[i]=read();
            if(d[i]<get_dis(a[i],b[i])) {puts("NO");return 0;}
            if(d[i]!=(int)2e6) flag1=0;
            if(d[i]!=get_dis(a[i],b[i])) flag3=0;
        }     
        if(flag1) {
            printf("1");
            return 0;
        } else if(flag2) {
            for(int i=1;i<=n;i++)
                rev[dep[i]]=i;
            for(int i=1;i<=m;i++) {
            	if(dep[a[i]]>dep[b[i]]) swap(a[i],b[i]);
                int dis=dep[b[i]]-dep[a[i]];
                if(d[i]<dis) {puts("NO");return 0;}
                dis=(d[i]-dis)/2;
                w[rev[dep[a[i]]-dis-1]]--;w[rev[dep[b[i]]+dis]]++;
            }
            get_ans(1);
            for(int i=1;i<=n;i++) {
                if(w[i]==m) {printf("%d
    ",i);return 0;}
            }
            puts("NO");
            return 0;
        } else if(flag3) {
            for(int i=1;i<=m;i++) {
                w[a[i]]++;w[b[i]]++;
                int lca=LCA(a[i],b[i]);
                w[lca]--;w[fa[lca]]--;
            }
            get_ans(1);
            for(int i=1;i<=n;i++) {
                if(w[i]==m) {printf("%d
    ",i);return 0;}
            }
            puts("NO");
        } else {
            for(int j=1;j<=n;j++) {
                bool f=1;
                for(int i=1;i<=m;i++) {
                    if(get_dis(j,a[i])+get_dis(j,b[i])>d[i])
                        {f=0;break;}
                }            
                if(f) {printf("%d
    ",j);return 0;}
            }
            puts("NO");
        }
        return 0;
    }
    
    /*
    一般
    5 3
    1 2
    2 3
    2 4
    3 5
    1 4 2
    5 5 5
    3 2 1
    
    5 3
    1 2
    2 3
    2 4
    3 5
    1 4 2000000
    5 5 2000000
    3 2 2000000
    
    6 4
    1 2
    2 4
    4 5
    5 3
    3 6
    2 5 4
    1 6 5
    4 3 2
    2 4 1
    
    6 3
    1 2
    2 4
    4 6
    2 3
    3 5
    2 5 2
    3 4 2
    1 6 3
    */
    

    正解


    求 dis(A,x) + dis(B,x) <= D ①

    设dist(x,A,B) (x到链(A,B)的最短距离)

    那么①式我们可转化为 求dist(x,A,B) * 2+dis(A,B) <=D

    dist(x,A,B) <= (D - dis(A,B) )/2

    dep[x] >= max【 0,dep[LCA(A,B)] - (D - dis(A,B) ) / 2 】——————啊其实和那个链上暴力有点像

    dep[x] >= max【 0,(dep[A]+dep[B] - D)/ 2】 ——化简

    w[i] = (dep[A]+dep[B] - D)/ 2

    如果一个点能作为答案,那么它必须满足所有的条件,满足dep>=每个w[i],我们找出最苛刻的条件,即其w[i]最大,而在能满足这个最苛刻条件的点集 中找出深度最小的点,因为满足这个条件的点集整体深度都很深,所以该点果最有可能满足其他点集的点就是深度最浅的点,然后判断这个点能不能满足其他条件限制,如果满足就是答案。

    #include <cmath>
    #include <cstdio>
    #include <iostream>
    using namespace std;
    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;
    }
    const int N=200005;
    bool flag1=1,flag2=1,flag3=1;
    int n,m,w[N];
    int to[N],nxt[N],hd[N],tot;
    inline void add(int x,int y){
    	to[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;
    }
    
    int siz[N],dep[N],fa[N],son[N];
    void dfs_son(int x,int f){
        siz[x]=1;fa[x]=f;dep[x]=dep[f]+1;
        for(int i=hd[x];i;i=nxt[i]){
            int y=to[i];
            if(y==f) continue;
            dfs_son(y,x);
            siz[x]+=siz[y];
            if(siz[y]>siz[son[x]]) son[x]=y;
        }
    }
    int top[N];
    void dfs_chain(int x,int tp){
        top[x]=tp;
        if(son[x]) dfs_chain(son[x],tp);
        for(int i=hd[x];i;i=nxt[i]){
            int y=to[i];
            if(y==fa[x]||y==son[x]) continue;
            dfs_chain(y,y);
        }
    }
    int LCA(int x,int y) {
        while(top[x]!=top[y]) {
            if(dep[top[x]]<dep[top[y]]) swap(x,y);
            x=fa[top[x]];
        }
        return dep[x]<dep[y]?x:y;
    }
    int a[N],b[N],d[N],rev[N];
    int get_dis(int x,int y) {
        return dep[x]+dep[y]-dep[LCA(x,y)]*2;
    }
    void get_ans(int x) {
        for(int i=hd[x];i;i=nxt[i]){
            int y=to[i];
            if(y==fa[x]) continue;
            get_ans(y);
            w[x]+=w[y];
        }    
    }
    int mx,depth,pos,ans;
    bool ch[N];
    int main() {
        n=read();m=read();
        for(int i=1,x,y;i<n;i++) {
            x=read();y=read(); 
            add(x,y);add(y,x);
        }
        dep[0]=-1;
        dfs_son(1,0);dfs_chain(1,1);
        for(int i=1;i<=m;i++) {
            a[i]=read();b[i]=read();d[i]=read();
            if(d[i]<get_dis(a[i],b[i])) {puts("NO");return 0;}
            w[i]=ceil((dep[a[i]]+dep[b[i]]-d[i])/2.0);
            if(w[i]>mx) pos=i,mx=w[i];
        }
        depth=0x3f3f3f3f;
        for(int i=1;i<=n;i++) {
            if(get_dis(i,a[pos])+get_dis(i,b[pos])<=d[pos]) ch[i]=1;
        }
        for(int i=1;i<=n;i++) {
            if(!ch[i]) continue;
            if(dep[i]<depth) ans=i,depth=dep[i];
        }
        for(int i=1;i<=m;i++) {
            if(get_dis(ans,a[i])+get_dis(ans,b[i])>d[i]) {
                puts("NO");return 0;
            }
        }
        cout<<ans<<endl;
        return 0;
    }
    
    /*
    5 3
    1 2
    2 3
    2 4
    3 5
    1 4 2
    5 5 5
    3 2 1
    
    */
    

    T3

    gugugu

  • 相关阅读:
    APP-SERVICE-SDK:setStorageSync:fail;at page/near/pages/shops/shops page lifeCycleMethod onUnload function
    css 别人找的css特效
    项目笔记2
    Win7如何删除需要管理员权限才能删除的文件夹
    Win7下C:UsersCortana以账户名称命名的系统文件夹用户名的修改
    Win10下C:UsersJohn以账户名称命名的系统文件夹用户名的修改
    windows10企业版怎么关闭自动更新
    给MySQL_5.7 配置环境变量
    用PE安装操作系统时:无法创建新的系统分区 也无法定位现有系统分区 的解决办法
    电脑内存和磁盘空间有什么区别与联系
  • 原文地址:https://www.cnblogs.com/ke-xin/p/13659976.html
Copyright © 2011-2022 走看看