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
Output
對每個詢問輸出一行表示答案,“Y”表示有解,“N”表示無解。Sample Input
5 51 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
NY
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)。下圖是由貝西視角所繪出的圖示。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
5T1: 對於一個三角形,可以用微積分的思想把它看成許多線段,然後最大面積肯定就是線段又大到小地把寬度排滿 由於線段長度是連續的,不是離散的,所以最後如果線段最小值為k,那麽高度大於等於k的部分一定會被選 放到一個三角形中,高度大於等於k的部分也對應一個寬度,把所有的寬度加起來如果正好等於L的話,那麽一定就是最優解。 由於存在EPS,我們可以用二分答案
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\n",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 }Code1
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\n",ans); 44 return 0; 45 }Code2
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\n"); 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\n"); 78 break; 79 } 80 } 81 if(!ok){ 82 printf("N\n"); 83 } 84 } 85 } 86 else{ 87 v[x]=y; 88 } 89 } 90 return 0; 91 }Code3
附加題:
這是一道平面掃描的題目
先正難則反,找非黃金三角形
按角度排序之後,對於每個點i,與原點做一條直線,然後同在直線一側的肯定是非黃金三角形,這樣用組合數就可以計算了
我們只需要考慮左側,因為後面的點考慮左側時會正好可以補上,做到不重不漏
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\n",(ll)n*(n-1)*(n-2)/6-ans); 47 return 0; 48 }Code4
總結:還模版題,模版個鬼啊,這麽難
NOIP2014-10-30模擬賽