NOIP2014-10-30模拟赛

T1:逗比三角形

【题目描述】

小J是一名OI退役滚粗文化课选手,他十分喜欢做题,尤其是裸题。他现在有一个二维盒子和一些二维三角形,这个盒子拥有无限的高度和L的宽度。而且他的三角形也都是一些锐角三角形或者是直角三角形。现在小J想把这些三角形放入盒子里,由于小J从txt大神犇那里学会了魔法,所以小J的三角形既可以无视盒子边界又可以重叠放置,但是必须有一条边紧贴盒子底面所在的直线。

现在小J想要最大化在盒子中的被三角形覆盖的区域的面积(即三角形间的重叠部分只算一遍),请问这个最大值应该是多少?

【输入格式】

一行一个整数T,代表数据组数。下面T部分,每部分第一行两个整数N,L分别代表三角形数量与盒子的宽度。下面N行每行三个整数ai,bi,ci表示三角形i的三条边长。

【输出格式】

T行,每行一个实数代表盒子内部被三角形覆盖的区域的面积的最大值。

T2:数三角形

Description

给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个。下图为4×4的网格上的一个三角形。

注意三角形的三点不能共线。

Input

输入一行,包含两个空格分隔的正整数m和n。

Output

输出一个正整数,为所求三角形数量。

Sample Input

2 2

Sample Output

76

数据范围
1<=m,n<=1000

T3:树上三角形

Description

给定一大小为n的有点权树,每次询问一对点(u,v),问是否能在u到v的简单路径上取三个点权,以这三个权值为边长构成一个三角形。同时还支持单点修改。

Input

第一行两个整数n、q表示树的点数和操作数
第二行n个整数表示n个点的点权
以下n-1行,每行2个整数a、b,表示a是b的父亲(以1为根的情况下)
以下q行,每行3个整数t、a、b
若t=0,则询问(a,b)
若t=1,则将点a的点权修改为b

Output

对每个询问输出一行表示答案,“Y”表示有解,“N”表示无解。

Sample Input

5 5
1 2 3 4 5
1 2
2 3
3 4
1 5
0 1 3
0 4 5
1 1 4
0 2 5
0 2 3

Sample Output

N
Y
Y
N

HINT

对于100%的数据,n,q<=100000,点权范围[1,2^31-1]

附加题:同名"数三角形"

Description

在一只大灰狼偷偷潜入Farmer Don的牛群被群牛发现后,贝西现在不得不履行着她站岗的职责。从她的守卫塔向下瞭望简直就是一件烦透了的事情。她决定做一些开发智力的小练习,防止她睡着了。想象牧场是一个X,Y平面的网格。她将N只奶牛标记为1…N (1 <= N <= 100,000),每只奶牛的坐标为X_i,Y_i (-100,000 <= X_i <= 100,000;-100,000 <= Y_i <= 100,000; 1 <= i <=N)。然后她脑海里想象着所有可能由奶牛构成的三角形。如果一个三角形完全包含了原点(0,0),那么她称这个三角形为“黄金三角形”。原点不会落在任何一对奶牛的连线上。另外,不会有奶牛在原点。给出奶牛的坐标,计算出有多少个“黄金三角形”。顺便解释一下样例,考虑五只牛,坐标分别为(-5,0), (0,2), (11,2), (-11,-6), (11,-5)。下图是由贝西视角所绘出的图示。 
NOIP2014-10-30模拟赛

Input

第一行:一个整数: N 第2到第N+1行: 每行两个整数X_i,Y_i,表示每只牛的坐标

Output

* 第一行: 一行包括一个整数,表示“黄金三角形的数量”

Sample Input

5
-5 0
0 2
11 2
-11 -6
11 -5

Sample Output

5

T1:
对于一个三角形,可以用微积分的思想把它看成许多线段,然后最大面积肯定就是线段又大到小地把宽度排满
由于线段长度是连续的,不是离散的,所以最后如果线段最小值为k,那么高度大于等于k的部分一定会被选
放到一个三角形中,高度大于等于k的部分也对应一个宽度,把所有的宽度加起来如果正好等于L的话,那么一定就是最优解。
由于存在EPS,我们可以用二分答案
 #include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#define MAXN 100005
#define EPS 1e-5
using namespace std;
double a[MAXN],b[MAXN],c[MAXN];
double S[MAXN],H[MAXN];
int n;
double LL;
bool cal(double h){
double ret=;
for(int i=;i<=n;i++){
if(H[i]>h){
ret+=(H[i]-h)*a[i]/H[i];
}
}
return (ret<=LL);
}
void solve(){
scanf("%d%lf",&n,&LL);
for(int i=;i<=n;i++){
scanf("%lf%lf%lf",&a[i],&b[i],&c[i]);
if(b[i]>c[i]){
swap(b[i],c[i]);
}
if(a[i]>b[i]){
swap(a[i],b[i]);
}
double p=(a[i]+b[i]+c[i])/2.0;
S[i]=sqrt(p*(p-a[i])*(p-b[i])*(p-c[i]));
H[i]=S[i]*/a[i];
}
double L=,R=;
double mid;
while(L+EPS<R){
mid=(L+R)/2.0;
if(cal(mid)){
R=mid;
}
else{
L=mid;
}
}
double ans=;
for(int i=;i<=n;i++){
if(H[i]>L){
ans+=(H[i]-L)*a[i]/H[i]*(H[i]-L)/2.0;
}
}
ans+=L*LL;
printf("%.6f\n",ans); }
int main()
{
freopen("sbtg10.in","r",stdin);
freopen("sbtg.out","w",stdout);
int T;
scanf("%d",&T);
for(int i=;i<=T;i++){
solve();
}
return ;
}

Code1


T2:

用组合数学的知识,先把所有的情况算出来,然后减去共线的情况即可

注意斜的用gcd算,不能用组合数了

还有就是注意不重不漏
 #include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define MAXN 1005005
#define ll long long
using namespace std;
ll C[MAXN][];
int g[][];
int Gcd(int x,int y){
if(g[x][y]){
return g[x][y];
}
return g[x][y]=((y==)?x:Gcd(y,x%y));
}
void make(){
for(int i=;i<MAXN;i++){
C[i][]=;
}
for(int i=;i<MAXN;i++){
for(int j=;j<=;j++){
C[i][j]=C[i-][j]+C[i-][j-];
}
}
}
int n,m;
int main()
{
make();
ll ans=;
scanf("%d%d",&n,&m);
n++;m++;
ans+=C[n*m][];
ans-=C[n][]*m;
ans-=C[m][]*n;
///!!!
for(int i=;i<=m;i++){
for(int j=;j<=n;j++){
int t=Gcd(i-,j-)-;
ans-=t*(m-i+)*(n-j+)*;
}
}
printf("%lld\n",ans);
return ;
}

Code2


T3:

这题好坑啊

设树链上的节点为a1,a2,a3,……,an

排一下序发现:

如果存在ai+ai+1>ai+2 那么就可以构成三角形了

即较小的两条边大于最大的边

然后考虑一下,如果出题目的人很变态,故意想卡你,使得这个数列尽可能多,但偏偏构成不了三角形(QAQ)

那么肯定是1 1 2 3 5 8 13 ……

斐波拉契数列,然后第50项就炸int了,由于数据又在int范围内,所以当节点数目超过50个时,再想卡你也卡不了,一定可以构成三角形

对于小于50的,直接暴力即可

 #include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define MAXN 100005
#define ll long long
using namespace std;
int v[MAXN];
int first[MAXN],Next[MAXN*],to[MAXN*],cnt;
int dep[MAXN],fa[MAXN];
int q[MAXN],top;
//double edge
int read(){
int ret=;
char c=getchar();
do{
ret=ret*+c-'';
c=getchar();
}while(''<=c&&c<='');
return ret;
}
void Add(int x,int y){
Next[++cnt]=first[x];first[x]=cnt;to[cnt]=y;
Next[++cnt]=first[y];first[y]=cnt;to[cnt]=x;
}
int n;
void dfs(int x){
for(int e=first[x];e;e=Next[e]){
int y=to[e];
if(y==fa[x]){
continue;
}
fa[y]=x;
dep[y]=dep[x]+;
dfs(y);
}
}
int main()
{
// freopen("sdtg2.in","r",stdin);
// freopen("my.out","w",stdout);
int T;
scanf("%d%d",&n,&T);
for(int i=;i<=n;i++){
scanf("%d",&v[i]);
}
for(int i=;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
Add(x,y);
}
dfs();
for(int i=;i<=T;i++){
int k,x,y;
scanf("%d%d%d",&k,&x,&y);
if(!k){
top=;
while(top<=){
if(dep[x]<dep[y]){
swap(x,y);
}
q[++top]=v[x];
if(x==y){
break;
}
x=fa[x];
}
if(top>){
printf("Y\n");
}
else{
int ok=;
sort(q+,q+top+);
for(int i=;i<=top-;i++){
if((ll)q[i]+q[i+]>q[i+]){
ok=;
printf("Y\n");
break;
}
}
if(!ok){
printf("N\n");
}
}
}
else{
v[x]=y;
}
}
return ;
}

Code3


附加题:

这是一道平面扫描的题目

先正难则反,找非黄金三角形

按角度排序之后,对于每个点i,与原点做一条直线,然后同在直线一侧的肯定是非黄金三角形,这样用组合数就可以计算了

我们只需要考虑左侧,因为后面的点考虑左侧时会正好可以补上,做到不重不漏

顺便说一下,向量a,b的叉积大于等于0(即a.x*b.y-a.y*b.x>=0)表示b在a的左边

 #include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#define MAXN 100005
#define ll long long
using namespace std;
struct Point{
ll x,y;
double angle;
Point(){
x=y=;
angle=;
}
friend bool operator < (const Point &p1,const Point &p2){
return (p1.angle<p2.angle);
}
friend bool operator > (const Point &p1,const Point &p2){
return !(p1<p2);
}
friend ll operator * (const Point &p1,const Point &p2){
return (p1.x*p2.y-p2.x*p1.y);
}
}s[MAXN];
int n;
int main()
{
// freopen("data.in","r",stdin);
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%lld%lld",&s[i].x,&s[i].y);
//atan222!!!
s[i].angle=atan2((double)s[i].y,(double)s[i].x);
}
sort(s+,s+n+);
int r=,t=;
ll ans=;
for(int i=;i<=n;i++){
while(r%n+!=i&&s[i]*s[r%n+]>=){
r++; t++;
}
ans+=(ll)t*(t-)/;
t--;
}
printf("%lld\n",(ll)n*(n-)*(n-)/-ans);
return ;
}

Code4

总结:还模版题,模版个鬼啊,这么难


上一篇:BZOJ 1003 物流运输 题解 【SPFA+DP】


下一篇:hdu 2243 考研路茫茫——单词情结 ac自动机+矩阵快速幂