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

原文地址:https://www.cnblogs.com/ke-xin/p/13659976.html