noip模拟【20171103】

T1

[dp]

以时间为关键字先排序。

F[i]表示到t[i]时刻,并且尽量拦截对应的子弹,最多可以拦到几发子弹,在自身没有死掉的情况下。如果向后转移时,前面多个点可以拦截的子弹数目都相同,那么选择时间最靠后的一个。

注意有些子弹根本无法拦截,所以初值赋值为极小值。

If(D(i,j) <= t[j]-t[i] /*可以选择*/|| (m1 – (t[i]-f[i])*d) < 0/*必须选择*/)f[i] = max(f[i],f[j] + 1);

并且在中途不会死亡的情况下,尽量靠后选择,取max。

【code】

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define File "Genji"
inline void file(){
    freopen(File".in","r",stdin);
    freopen(File".out","w",stdout);
} 
inline int read(){
    int x = 0,f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch=='-')f = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = (x<<1) + (x<<3) + ch-'0'; ch = getchar();}
    return x*f;
}
const int mxn = 2e3 + 5;
int n,m1,m2,d;
struct P{
    double x,y,t;
}p[mxn];
inline bool cmp(P t1,P t2){
    return t1.t < t2.t;
}
int f[mxn];
double x_0,y_0;

inline double dis(double x1,double y1,double x2,double y2){
    return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
}
inline double T(double t1,double t2){
    return (t1-t2)*(t1-t2);
}
int mx(0);

int main(){
    file();
    n = read(),m1 = read(),m2 = read(),d = read();
    scanf("%lf%lf",&p[0].x,&p[0].y);
    p[0].t = 0.0;
    for(int i = 1;i <= n; ++i){
        double x,y,t;
        scanf("%lf%lf%lf",&x,&y,&t);
        p[i] = (P){x,y,t};
    }
    sort(p+1,p+n+1,cmp);

    memset(f,0xcf,sizeof f);
    f[0] = 0;

    for(int i = 1;i <= n; ++i){
        double x1 = p[i].x,y1 = p[i].y,t1 = p[i].t;

        for(int j = 0;j < i; ++j){
            double x2 = p[j].x,y2 = p[j].y,t2 = p[j].t;
            if(dis(x1,y1,x2,y2) <= T(t1,t2)) 
                f[i] = max(f[i],f[j] + 1); 
        }
        mx = max(mx,f[i]);
        if(mx*d >= m2){
            printf("Y %.2lf\n",t1);
            return 0;
        } 
        if((i-mx)*d >= m1){
            printf("N %.2lf\n",t1);
            return 0;
        }
    }
    printf("%d\n",mx);
    return 0;
}
/*
3 10 30 5
0 0
1 2 3
1 1 1
2 1 4
*/
View Code

 

 

T2

[数学,二分]

对于每个x[i],x0取到x[i]的时候单个贡献取到最小值,非x[i]时成单增或单减,其函数图像类似于二次函数y = a*x^2。其导函数为单增,易知对于每个x[i]来讲,x0在实数范围都是单增的。那么我们可以对于x0进行二分,每个导函数进行相加比较,求出取到贡献最小的x0。

【code】 

#include<bits/stdc++.h>
using namespace std;
#define ld long double
#define File "76"
inline void file(){
    freopen(File".in","r",stdin);
    freopen(File".out","w",stdout);
} 
inline int read(){
    int x = 0,f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch=='-')f = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = (x<<1) + (x<<3) + ch-'0'; ch = getchar();}
    return x*f;
}
const int mxn = 1e5 + 10;
int n;
ld x[mxn];
int y[mxn],z[mxn];
ld l,r,m,ret1,ret2;

int main(){
    file();    
    n=read();
    for(int i=1;i<=n;++i){
        scanf("%lf",&x[i]);
        y[i]=read(),z[i]=read();
    }
    
    l=-1001,r=1001;
    for(int i = 1;i <= 30; ++i){
        m = (l+r)/2,ret1 = ret2 = 0;
        for(int j = 1;j <= n; ++j){
            if(m <= x[j]){
                if(y[j]) ret1 += y[j]*expl(logl(x[j]-m)*(y[j]-1));//以e为底 防止溢出
            }
            else{
                if(z[j]) ret2 += z[j]*expl(logl(m-x[j])*(z[j]-1));
            }
        }
        ret1 > ret2 ? l = m:r = m;
    }
    printf("%.2lf\n",l);
    return 0;
}
/*
2
3 2 3
-3 3 2
*/
View Code

 

 

T3

[并查集]

将一样强的炮台放入一个并查集中,如果有炮台比并查集中的炮台强,则并查集中的炮台全部不可行。并查集扫完之后再判断可行炮台的数量。

 【code】

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define inf 1001.0
#define File "76"
inline void file(){
    freopen(File".in","r",stdin);
    freopen(File".out","w",stdout);
} 
inline int read(){
    int x = 0,f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch=='-')f = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = (x<<1) + (x<<3) + ch-'0'; ch = getchar();}
    return x*f;
}
const int mxn = 1e5 + 5;
int n,m;
int fa[mxn],sz[mxn];
int getf(int x){
    if(x == fa[x]) return x;
    return fa[x] = getf(fa[x]); 
}
/*
一样强就加入到一个并查集里
已知强弱,就无须管弱的。。。 
*/
int a[mxn],b[mxn];
int main(){
    file();
    n = read(),m = read();
    for(int i = 1;i <= n; ++i) fa[i] = i,sz[i] = 1;
    for(int i = 1;i <= m; ++i){
        int tp = read(),x = read(),y = read();
        if(tp){
            if(x == y) continue;
            x = getf(x),y = getf(y);
            if(sz[x] > sz[y]) swap(x,y);
            fa[y] = x,sz[x] += sz[y];
        }else a[y] = 1;//标记强的 
    }
    for(int i = 1;i <= n; ++i) b[getf(i)] |= a[i];

    int ans(0);
    for(int i = 1;i <= n; ++i){
        if(fa[i]==i && !b[i]){
            if(ans){
                puts("0"); return 0;
            }
            ans = sz[i];
        }  
    } 
    printf("%d\n",ans);
    return 0;
}
/*
2 1
1 1 2
*/
View Code

 

posted @ 2019-08-14 18:35  ve-2021  阅读(132)  评论(0编辑  收藏  举报