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
Input
Output
Sample Input
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
Y
Y
N
HINT
对于100%的数据,n,q<=100000,点权范围[1,2^31-1]
附加题:同名"数三角形"
Description
Input
Output
Sample Input
-5 0
0 2
11 2
-11 -6
11 -5
Sample Output
1 #include<cstdio> 2 #include<cstdlib> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #define MAXN 100005 7 #define EPS 1e-5 8 using namespace std; 9 double a[MAXN],b[MAXN],c[MAXN]; 10 double S[MAXN],H[MAXN]; 11 int n; 12 double LL; 13 bool cal(double h){ 14 double ret=0; 15 for(int i=1;i<=n;i++){ 16 if(H[i]>h){ 17 ret+=(H[i]-h)*a[i]/H[i]; 18 } 19 } 20 return (ret<=LL); 21 } 22 void solve(){ 23 scanf("%d%lf",&n,&LL); 24 for(int i=1;i<=n;i++){ 25 scanf("%lf%lf%lf",&a[i],&b[i],&c[i]); 26 if(b[i]>c[i]){ 27 swap(b[i],c[i]); 28 } 29 if(a[i]>b[i]){ 30 swap(a[i],b[i]); 31 } 32 double p=(a[i]+b[i]+c[i])/2.0; 33 S[i]=sqrt(p*(p-a[i])*(p-b[i])*(p-c[i])); 34 H[i]=S[i]*2/a[i]; 35 } 36 double L=0,R=1000000; 37 double mid; 38 while(L+EPS<R){ 39 mid=(L+R)/2.0; 40 if(cal(mid)){ 41 R=mid; 42 } 43 else{ 44 L=mid; 45 } 46 } 47 double ans=0; 48 for(int i=1;i<=n;i++){ 49 if(H[i]>L){ 50 ans+=(H[i]-L)*a[i]/H[i]*(H[i]-L)/2.0; 51 } 52 } 53 ans+=L*LL; 54 printf("%.6f ",ans); 55 56 } 57 int main() 58 { 59 freopen("sbtg10.in","r",stdin); 60 freopen("sbtg.out","w",stdout); 61 int T; 62 scanf("%d",&T); 63 for(int i=1;i<=T;i++){ 64 solve(); 65 } 66 return 0; 67 }
T2:
用组合数学的知识,先把所有的情况算出来,然后减去共线的情况即可
注意斜的用gcd算,不能用组合数了
1 #include<cstdio> 2 #include<cstdlib> 3 #include<algorithm> 4 #include<cstring> 5 #define MAXN 1005005 6 #define ll long long 7 using namespace std; 8 ll C[MAXN][4]; 9 int g[1005][1005]; 10 int Gcd(int x,int y){ 11 if(g[x][y]){ 12 return g[x][y]; 13 } 14 return g[x][y]=((y==0)?x:Gcd(y,x%y)); 15 } 16 void make(){ 17 for(int i=0;i<MAXN;i++){ 18 C[i][0]=1; 19 } 20 for(int i=1;i<MAXN;i++){ 21 for(int j=1;j<=3;j++){ 22 C[i][j]=C[i-1][j]+C[i-1][j-1]; 23 } 24 } 25 } 26 int n,m; 27 int main() 28 { 29 make(); 30 ll ans=0; 31 scanf("%d%d",&n,&m); 32 n++;m++; 33 ans+=C[n*m][3]; 34 ans-=C[n][3]*m; 35 ans-=C[m][3]*n; 36 ///!!! 37 for(int i=2;i<=m;i++){ 38 for(int j=2;j<=n;j++){ 39 int t=Gcd(i-1,j-1)-1; 40 ans-=t*(m-i+1)*(n-j+1)*2; 41 } 42 } 43 printf("%lld ",ans); 44 return 0; 45 }
T3:
这题好坑啊
设树链上的节点为a1,a2,a3,……,an
排一下序发现:
如果存在ai+ai+1>ai+2 那么就可以构成三角形了
即较小的两条边大于最大的边
然后考虑一下,如果出题目的人很变态,故意想卡你,使得这个数列尽可能多,但偏偏构成不了三角形(QAQ)
那么肯定是1 1 2 3 5 8 13 ……
斐波拉契数列,然后第50项就炸int了,由于数据又在int范围内,所以当节点数目超过50个时,再想卡你也卡不了,一定可以构成三角形
对于小于50的,直接暴力即可
1 #include<cstdio> 2 #include<cstdlib> 3 #include<algorithm> 4 #include<cstring> 5 #define MAXN 100005 6 #define ll long long 7 using namespace std; 8 int v[MAXN]; 9 int first[MAXN],Next[MAXN*2],to[MAXN*2],cnt; 10 int dep[MAXN],fa[MAXN]; 11 int q[MAXN],top; 12 //double edge 13 int read(){ 14 int ret=0; 15 char c=getchar(); 16 do{ 17 ret=ret*10+c-'0'; 18 c=getchar(); 19 }while('0'<=c&&c<='9'); 20 return ret; 21 } 22 void Add(int x,int y){ 23 Next[++cnt]=first[x];first[x]=cnt;to[cnt]=y; 24 Next[++cnt]=first[y];first[y]=cnt;to[cnt]=x; 25 } 26 int n; 27 void dfs(int x){ 28 for(int e=first[x];e;e=Next[e]){ 29 int y=to[e]; 30 if(y==fa[x]){ 31 continue; 32 } 33 fa[y]=x; 34 dep[y]=dep[x]+1; 35 dfs(y); 36 } 37 } 38 int main() 39 { 40 // freopen("sdtg2.in","r",stdin); 41 // freopen("my.out","w",stdout); 42 int T; 43 scanf("%d%d",&n,&T); 44 for(int i=1;i<=n;i++){ 45 scanf("%d",&v[i]); 46 } 47 for(int i=1;i<n;i++){ 48 int x,y; 49 scanf("%d%d",&x,&y); 50 Add(x,y); 51 } 52 dfs(1); 53 for(int i=1;i<=T;i++){ 54 int k,x,y; 55 scanf("%d%d%d",&k,&x,&y); 56 if(!k){ 57 top=0; 58 while(top<=50){ 59 if(dep[x]<dep[y]){ 60 swap(x,y); 61 } 62 q[++top]=v[x]; 63 if(x==y){ 64 break; 65 } 66 x=fa[x]; 67 } 68 if(top>50){ 69 printf("Y "); 70 } 71 else{ 72 int ok=0; 73 sort(q+1,q+top+1); 74 for(int i=1;i<=top-2;i++){ 75 if((ll)q[i]+q[i+1]>q[i+2]){ 76 ok=1; 77 printf("Y "); 78 break; 79 } 80 } 81 if(!ok){ 82 printf("N "); 83 } 84 } 85 } 86 else{ 87 v[x]=y; 88 } 89 } 90 return 0; 91 }
附加题:
这是一道平面扫描的题目
先正难则反,找非黄金三角形
按角度排序之后,对于每个点i,与原点做一条直线,然后同在直线一侧的肯定是非黄金三角形,这样用组合数就可以计算了
我们只需要考虑左侧,因为后面的点考虑左侧时会正好可以补上,做到不重不漏
顺便说一下,向量a,b的叉积大于等于0(即a.x*b.y-a.y*b.x>=0)表示b在a的左边
1 #include<cstdio> 2 #include<cstdlib> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #define MAXN 100005 7 #define ll long long 8 using namespace std; 9 struct Point{ 10 ll x,y; 11 double angle; 12 Point(){ 13 x=y=0; 14 angle=0; 15 } 16 friend bool operator < (const Point &p1,const Point &p2){ 17 return (p1.angle<p2.angle); 18 } 19 friend bool operator > (const Point &p1,const Point &p2){ 20 return !(p1<p2); 21 } 22 friend ll operator * (const Point &p1,const Point &p2){ 23 return (p1.x*p2.y-p2.x*p1.y); 24 } 25 }s[MAXN]; 26 int n; 27 int main() 28 { 29 // freopen("data.in","r",stdin); 30 scanf("%d",&n); 31 for(int i=1;i<=n;i++){ 32 scanf("%lld%lld",&s[i].x,&s[i].y); 33 //atan222!!! 34 s[i].angle=atan2((double)s[i].y,(double)s[i].x); 35 } 36 sort(s+1,s+n+1); 37 int r=1,t=0; 38 ll ans=0; 39 for(int i=1;i<=n;i++){ 40 while(r%n+1!=i&&s[i]*s[r%n+1]>=0){ 41 r++; t++; 42 } 43 ans+=(ll)t*(t-1)/2; 44 t--; 45 } 46 printf("%lld ",(ll)n*(n-1)*(n-2)/6-ans); 47 return 0; 48 }
总结:还模版题,模版个鬼啊,这么难