noip模拟66
作者:互联网
考试过程:可能受到了自己生病的一些影响,这次考试状态不是很好。做题的时候比较困。我按顺序开题,首先是T1,这题挺有意思,显然是一道DP题,但是刚开始我想的是类似于\(f_{i,j}\)表示第1个序列选\(i\)个,第二个序列选\(j\)个的最大值,但是这么转移不仅复杂度很高并且转移也很麻烦。我又想了想觉得可以将两个序列分开考虑,最后再合并,反正只要体积是一定的就是对的,然后就切了。
T2,这题考场上实在没什么思路,就打了个暴搜。T3,我觉得部分分挺多,但是我读错题了,导致我获得了\(0pts\)的高分...。总之,以后还是要多注意身体,生病啥的都会影响考试状态。
T1 接力比赛
思路:上面说的差不多了,我将左右两边分开考虑,我的朴素DP是\(f_{i,j}\)表示第一个序列以\(i\)结尾的总体积为\(j\)的最大值,\(g_{i,j}\)同理,那么转移是显然的\(f_{i,j}=max(f_{i,j},f_{k,j-w_i}+v_i)\),这样的复杂度是\(n^2\times U\)的,复杂度比较高,然后我观察这个DP式子,发现这好像是一个背包,然后我就按照背包DP的思路优化了一下\(f_{i,j}=max(f_{i-1,j},f{i-1,j-w_i}+v_i)\),这样就把复杂度降掉一个\(n\),然后卡卡上界这道题就切了。
代码如下:
AC_code
#include<bits/stdc++.h>
#define int long long
#define re register int
#define ii inline int
#define iv inline void
#define f() cout<<"fuck"<<endl
using namespace std;
const int N=1e6+10;
const int M=1010;
const int INF=1e18;
int n,m,ans;
int f[N],g[N],s1[N],s2[N];
struct node
{
int w,v;
}c1[M],c2[M];
ii read()
{
int x=0;char ch=getchar();bool f=1;
while(ch<'0' or ch>'9')
{
if(ch=='-') f=0;
ch=getchar();
}
while(ch>='0' and ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return f?x:(-x);
}
signed main()
{
freopen("game.in","r",stdin),freopen("game.out","w",stdout);
n=read(),m=read();
for(re i=1;i<=n;i++) c1[i]=(node){read(),read()},s1[i]=s1[i-1]+c1[i].w;
for(re i=1;i<=m;i++) c2[i]=(node){read(),read()},s2[i]=s2[i-1]+c2[i].w;
int up=max(s1[n],s2[m]);
for(re i=1;i<=up;i++) f[i]=g[i]=-INF;
f[c1[1].w]=c1[1].v;
for(re i=2;i<=n;i++)
for(re p=s1[i];p>=c1[i].w;p--)
f[p]=max(f[p],f[p-c1[i].w]+c1[i].v);
g[c2[1].w]=c2[1].v;
for(re i=2;i<=m;i++)
for(re p=s2[i];p>=c2[i].w;p--)
g[p]=max(g[p],g[p-c2[i].w]+c2[i].v);
for(re i=1;i<=up;i++) ans=max(ans,f[i]+g[i]);
printf("%lld\n",ans);
return 0;
}
T2 树上竞技
留坑
T3 虚构推理
思路:我在考场上看错题了,这道题其实是将时针与时针的夹角比较,分针和分针的夹角比较,然后取个\(max\),但是我直接把当前时间点的角度进行了比较。知道了题意,那我们考虑做法,首先我们可以枚举\(i,j,k\)表示时,分,秒。然后计算取最小的最大值即可。
计算的话利用一个\(upper_bound\)将排序后的数组二分查找即可。
注意1.我们要将边界设为\(a_0=a_n,a_{n+1}=a_1\),这样可以避免很多问题。
2.在计算角度的时候我们利用了\(t2=t1+180\),但是要计算夹角我们要用\(180-t2-a_p\),不能直接用\(t1-a_p\),因为这样算出来的夹角可能是钝角。
代码如下:
AC_code
#include<bits/stdc++.h>
#define re register int
#define ii inline int
#define iv inline void
#define f() cout<<"fuck"<<endl
#define head heeadd
#define next net
#define D double
using namespace std;
const int N=5e4+10;
const double eps=1e-6;
int n;
double ans=999999999.999999;
int h[N],m[N],s[N];
double du[N],dh[N],dm[N];
char ch[N];
ii read()
{
int x=0;char ch=getchar();bool f=1;
while(ch<'0' or ch>'9')
{
if(ch=='-') f=0;
ch=getchar();
}
while(ch>='0' and ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return f?x:(-x);
}
signed main()
{
freopen("unreal.in","r",stdin),freopen("unreal.out","w",stdout);
n=read();
for(re i=1;i<=n;i++)
{
scanf("%s",ch+1);
int len=strlen(ch+1),tmp=0,flag=0;
for(re j=1;j<=len;j++)
{
if(ch[j]==':')
{
if(flag==0) h[i]=tmp;
else if(flag==1) m[i]=tmp;
++flag,tmp=0;
continue;
}
tmp=tmp*10+ch[j]-'0';
}
s[i]=tmp;
if(h[i]>=12) h[i]=h[i]%12;
dh[i]=(double)h[i]*30.00000+(double)m[i]*0.50000+(double)s[i]*0.5/60.0;
dm[i]=(double)m[i]*6.00000+(double)s[i]*0.10000;
}
sort(dh+1,dh+n+1),sort(dm+1,dm+n+1);
dh[0]=dh[n],dh[n+1]=dh[1];
dm[0]=dm[n],dm[n+1]=dm[1];
for(re i=0;i<12;i++)
{
for(re j=0;j<60;j++)
{
for(double k=0.00000;k<60;k+=0.01)
{
double maxx=0.000,t1,t2;
int pos;
t1=(double)i*30.0000+(double)j*0.50000+k*0.5/60.0;
t2=t1+180.00;
if(t2>=360) t2-=360.00;
pos=upper_bound(dh+1,dh+n+1,t2)-dh;
double tmp1=180-(dh[pos]-t2);
double tmp2=180-(t2-dh[pos-1]);
if(tmp1>=360) tmp1-=360;if(tmp1<0) tmp1+=360;
if(tmp2>=360) tmp2-=360;if(tmp2<0) tmp2+=360;
t1=(double)j*6.00+k*0.10;
t2=t1+180.00;
if(t2>=360) t2-=360.00;
pos=upper_bound(dm+1,dm+n+1,t2)-dm;
double tmp3=180-(dm[pos]-t2);
double tmp4=180-(t2-dm[pos-1]);
if(tmp3>=360) tmp3-=360;if(tmp3<0) tmp3+=360;
if(tmp4>=360) tmp4-=360;if(tmp4<0) tmp4+=360;
tmp1=min(tmp1,360-tmp1);
tmp2=min(tmp2,360-tmp2);
tmp3=min(tmp3,360-tmp3);
tmp4=min(tmp4,360-tmp4);
maxx=max(max(tmp1,tmp2),max(tmp3,tmp4));
ans=min(ans,maxx);
}
}
}
printf("%.6lf\n",ans);
return 0;
}
标签:dm,noip,dh,double,t2,360,66,模拟,define 来源: https://www.cnblogs.com/WindZR/p/15363331.html