noip66
T1
前缀和优化+背包。
两班都做一遍,最后相同体积合并即可。
T2
考场想法:没啥好说的,因为是暴力。
然而读错题了,20pts也没了。。。
题目里的每种情况指的是集合点不同,让求的是,对于每一个集合点,求出其最小代价,并给所有点的最小代价求个总和。
正解:
Code
#include<cstdio>
#include<cctype>
#define MAX 1000003
#define re register
#define int long long
const int mod = 1e9+7;
namespace some
{
struct stream
{
template<typename type>inline stream &operator >>(type &s)
{
bool w=0; s=0; char ch=getchar();
while(!isdigit(ch)){ w|=ch=='-'; ch=getchar(); }
while(isdigit(ch)){ s=(s<<1)+(s<<3)+(ch^48); ch=getchar(); }
return s=w?-s:s,*this;
}
}cin;
int n,m;
struct graph
{
int next;
int to;
}edge[MAX<<1];
int cnt=1,head[MAX];
auto add = [](int u,int v) -> void { edge[++cnt] = (graph){head[u],v},head[u] = cnt; };
auto fd = [](int &a,int b) { a = b-mod+a>=0?a+b-mod:a+b; };
}using namespace some;
namespace OMA
{
int fac[MAX],inv[MAX];
auto quickpow = [](int a,int b,int res = 1) -> int
{
while(b)
{
if(b&1)
{ res = res*a%mod; }
a = a*a%mod,b >>= 1;
}
return res;
};
auto C = [](int n,int m) -> int { return n<m?0:fac[n]*inv[n-m]%mod*inv[m]%mod; };
int size[MAX],g[MAX],ans;
void dfs(int u,int fa)
{
size[u] = 1;
for(re int i=head[u],v; i; i=edge[i].next)
{
v = edge[i].to;
if(v!=fa)
{
dfs(v,u);
size[u] += size[v];
}
}
fd(ans,(g[size[u]]+g[n-size[u]])%mod+(m&1?0:C(size[u],m/2)*C(n-size[u],m/2)%mod*m/2%mod));
//printf("%lld\n",ans);
}
auto main = []() -> signed
{
freopen("meeting.in","r",stdin); freopen("meeting.out","w",stdout);
cin >> n >> m;
for(re int v=2,u; v<=n; v++)
{ cin >> u; add(u,v),add(v,u); }
fac[0] = inv[0] = 1;
for(re int i=1; i<=n; i++)
{ fac[i] = fac[i-1]*i%mod; }
inv[n] = quickpow(fac[n],mod-2);
for(re int i=n-1; i; i--)
{ inv[i] = inv[i+1]*(i+1)%mod; }
g[1] = (m>2)*C(n-1,m-1);
for(re int i=1; i<=n-1; i++)
{ g[i+1] = (g[i]-C(i-1,(m-1)/2-1)*C(n-i-1,m-(m-1)/2-1)%mod+mod)%mod,g[i] = g[i]*i%mod; }
g[n] = n*g[n]%mod;
//for(re int i=1; i<=n; i++) { printf("%lld\n",g[i]); }
dfs(1,0);
printf("%lld\n",ans);
return 0;
};
}
signed main()
{ return OMA::main(); }
貌似是个比较常见的套路。
T3
考场想法:显然枚举可做,于是枚举,死活过不了第二个样例...于是直接交了就。
秒竟然能枚举小数???出题人不讲武德...
正解;
二分不会。
所以用b哥的枚举....
枚举时分秒,枚举到当前的这个角度,给它转180度,找这个角度的前驱和后继,两个中跟枚举的那个角最大的就是当前的答案。
找前驱后继可以用二分查找,算出角度后记得拿360°减一下再算一个出来。
可以自己画个图理解一下。
Code
#include<cstdio>
#include<cctype>
#include<algorithm>
#define MAX 50003
#define re register
using std::sort;
using std::upper_bound;
namespace some
{
struct stream
{
template<typename type>inline stream &operator >>(type &s)
{
bool w=0; s=0; char ch=getchar();
while(!isdigit(ch)){ w|=ch=='-'; ch=getchar(); }
while(isdigit(ch)){ s=(s<<1)+(s<<3)+(ch^48); ch=getchar(); }
return s=w?-s:s,*this;
}
}cin;
auto min = [](double a,double b) { return a<b?a:b; };
auto max = [](double a,double b) { return a>b?a:b; };
}using namespace some;
namespace OMA
{
int n;
double beta[MAX],alpha[MAX];
double theta,gamma,ans=361.0;
auto main = []() -> signed
{
freopen("unreal.in","r",stdin); freopen("unreal.out","w",stdout);
cin >> n;
for(re int i=1,h,m,s; i<=n; i++)
{
cin >> h >> m >> s; h %= 12;
beta[i] = m*6.0+s*0.1,alpha[i] = h*30.0+m*0.5+s*0.5/60.0;
}
sort(beta+1,beta+1+n),sort(alpha+1,alpha+1+n);
beta[0] = beta[n],beta[n+1] = beta[1];
alpha[0] = alpha[n],alpha[n+1] = alpha[1];
for(re int h=0,p1,p2; h<12; h++)
{
for(re int m=0; m<60; m++)
{
for(re double s=0,rec1,rec2,rec3,rec4; s<60; s+=0.01)
{
// double h=7,m=12,s=59.5,rec1,rec2,rec3,rec4;int p1,p2;
theta = m*6.0+s*0.1,gamma = h*30.0+m*0.5+s/120.0;
if(theta>=180.0) { theta -= 180.0; }
else { theta += 180.0; }
if(gamma>=180.0) { gamma -= 180.0; }
else { gamma += 180.0; }
p1 = upper_bound(beta+1,beta+1+n,theta)-beta-1;
p2 = upper_bound(alpha+1,alpha+1+n,gamma)-alpha-1; // pre
rec1 = 180.0-theta+beta[p1],rec2 = 180.0-beta[p1+1]+theta;
rec3 = 180.0-gamma+alpha[p2],rec4 = 180.0-alpha[p2+1]+gamma;
if(rec1<0.0) { rec1 += 360.0; }
else if(rec1>=360.0) { rec1 -= 360.0; }
if(rec2<0.0) { rec2 += 360.0; }
else if(rec2>=360.0) { rec2 -= 360.0; }
if(rec3<0.0) { rec3 += 360.0; }
else if(rec3>=360.0) { rec3 -= 360.0; }
if(rec4<0.0) { rec4 += 360.0; }
else if(rec4>=360.0) { rec4 -= 360.0; }
//printf("%0.5lf %0.5lf %0.5lf %0.5lf\n",rec1,rec2,rec3,rec4);
ans = min(ans,max(max(min(rec1,360.0-rec1),min(rec2,360.0-rec2)),max(min(rec3,360.0-rec3),min(rec4,360.0-rec4))));
//if(ans==max(max(min(rec1,360.0-rec1),min(rec2,360.0-rec2)),max(min(rec3,360.0-rec3),min(rec4,360.0-rec4))))
}
}
}
printf("%0.5lf\n",ans);
return 0;
};
}
signed main()
{ return OMA::main(); }
T4
一点不会,咕了。