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 */
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 */
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 */
G102的孤儿们都要好好的啊。