P100
zhx
竞赛时间:????年??月??日??:??-??:??
题目名称 |
a |
b |
c |
名称 |
a |
b |
c |
输入 |
a.in |
b.in |
c.in |
输出 |
a.out |
b.out |
c.out |
每个测试点时限 |
1s |
1s |
1s |
内存限制 |
256MB |
256MB |
256MB |
测试点数目 |
6 |
100 或 200 |
10 |
每个测试点分值 |
16 或者 17 |
1 或 0.5 |
10 |
是否有部分分 |
无 |
无 |
无 |
题目类型 |
传统 |
传统 |
传统 |
注意事项(请务必仔细阅读):
P100 zhxa
T1 a
【问题描述】
你是能看到第一题的 friends 呢。
——hja
给你一个只有小括号和中括号和大括号的括号序列,问该序列是否合法。
【输入格式】
一行一个括号序列。
【输出格式】
如果合法,输出 OK,否则输出 Wrong。
【样例输入】
[(])
【样例输出】
Wrong
【数据范围与规定】
对于70%的数据,1 ≤N≤ 100。
对于100%的数据,1 ≤N≤ 10000,所有单词由大写字母组成。
栈模拟
1 #include <cstring> 2 #include <cstdio> 3 4 const int N(10005); 5 char s[N],stack[N]; 6 int top; 7 8 int Presist() 9 { 10 freopen("a.in","r",stdin); 11 freopen("a.out","w",stdout); 12 scanf("%s",s+1); int n=strlen(s+1); 13 if(n&1) { printf("Wrong"); return 0; } 14 for(int i=1; i<=n; ++i) 15 { 16 if(s[i]=='[') stack[++top]='['; 17 else if(s[i]=='(') stack[++top]='('; 18 else if(s[i]==']') 19 { 20 if(!top||stack[top--]!='[') 21 { 22 printf("Wrong"); 23 return 0; 24 } 25 } 26 else if(s[i]==')') 27 { 28 if(!top||stack[top--]!='(') 29 { 30 printf("Wrong"); 31 return 0; 32 } 33 } 34 } 35 printf("OK"); 36 return 0; 37 } 38 39 int Aptal=Presist(); 40 int main(int argc,char**argv){;}
T2 b
【问题描述】
你是能看到第二题的 friends 呢。
——laekov
Yjq 想要将一个长为 宽为 的矩形棺材(棺材表面绝对光滑,所以棺材可以任意的滑动)拖过一个 L 型墓道。
如图所示,L 型墓道两个走廊的宽度分别是 和 ,呈 90°,并且走廊的长度远大于 。
现在 Hja 想知道对于给定的a , b, l,最大的 是多少,如果无论如何棺材都不可能通过,则输出"My poor head =("
【输入格式】
第一行三个用空格分隔的整数a , b , l,意义如题目所示。
【输出格式】
输出最大的可能的 w,保留七位小数,如果无论如何棺材都不可能通过,则输出"My poor head =("。
【样例输入 1】
2 2 1
【样例输出 1】
1.0000000
【样例输入 2】
2 2 2
【样例输出 2】
2.0000000
【样例输入 3】
2 2 3
【样例输出 3】
1.3284271
【样例输入 4】
2 2 6
【样例输出 4】
My poor head =(
【数据范围与规定】
对于100%的数据,1 ≤ a,b l,≤ 104。
设直线解析式为 y=(-n/m)* x+n
整理,得:n * x + m * y - n * m = 0
点(b,a)到直线的距离为:| b * n + a * m - n * m | / L
(L : 根号下(n^2 + m^2)=L)
棺材能够在这里拐弯
直观上感受就是棺材拐弯的全程不被点(b,a)卡住
所以 最优解 是 b * n + a * m - n * m / L 的最小值
为什么这里把绝对值去掉?
因为 当式子<0 时,直线到了点的右上方,就是不合法解,此时棺材不能通过
单峰函数求最小值,三分法每次去掉大的一部分
注意特判直接横着/竖着就能拖过去的情况
1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 5 using namespace std; 6 const double eps=1e-9; 7 8 int a,b,l; 9 10 double f(double n) 11 { 12 double m=sqrt(1.0*l*l-n*n); 13 return (b*n+a*m-n*m)/l; 14 } 15 16 int main() 17 { 18 freopen("b.in","r",stdin); 19 freopen("b.out","w",stdout); 20 scanf("%d%d%d",&a,&b,&l); 21 if(a>=l && b>=l) { printf("%d.0000000",l); return 0; } 22 if(a>=l) { printf("%d.0000000",b); return 0; } 23 if(b>=l) { printf("%d.0000000",a); return 0; } 24 double L=0,R=l,ans=-1e18,mid1,mid2,t1,t2; 25 int T=100; 26 while(T--) 27 { 28 mid1=(R-L)/3+L; mid2=L+R-mid1; 29 t1=f(mid1); t2=f(mid2); 30 if(t1<0 || t2<0) { printf("My poor head =("); return 0; } 31 if(t1<t2) ans=t1,R=mid2; 32 else ans=t2,L=mid1; 33 } 34 printf("%.7lf",ans); 35 }
T3 c
【问题描述】
你是能看到第三题的 friends 呢。
——aoao
树是个好东西,删掉树一条边要 1 的代价,随便再加一条边有 1 的代价,求最小的代价把树变成环。
【输入格式】
第一行一个整数 N,代表树的点数。
接下来 N− 1行,每行两个数代表树的一条边。
【输出格式】
一行一个整数代表答案。
【样例输入】
4
1 2
2 3
2 4
【样例输出】
3
【数据规模与约定】
对于30%的数据,1 ≤N ≤ 10。对于60%的数据,1 ≤N ≤ 1000。
对于100%的数据,1 ≤ N≤ 100000。
1 #include <cstdio> 2 #include <map> 3 4 inline void read(int &x) 5 { 6 x=0; register char ch=getchar(); 7 for(; ch>'9'||ch<'0'; ) ch=getchar(); 8 for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0'; 9 } 10 11 const int N(100005); 12 13 std::map<int,bool>cut[N]; 14 15 int n,cnt[N],ans,tmp; 16 int head[N],sumedge; 17 struct Edge { 18 int v,next; 19 Edge(int v=0,int next=0):v(v),next(next){} 20 }edge[N<<1]; 21 inline void ins(int u,int v) 22 { 23 cnt[u]++; cnt[v]++; 24 edge[++sumedge]=Edge(v,head[u]); head[u]=sumedge; 25 edge[++sumedge]=Edge(u,head[v]); head[v]=sumedge; 26 } 27 28 int tim,dfn[N]; 29 inline void Cutedge(int u) 30 { 31 int maxx=-1,pos; 32 for(int v,i=head[u]; i; i=edge[i].next) 33 { 34 v=edge[i].v; 35 if(cnt[v]>maxx&&!cut[u][v]&&!cut[v][u]) maxx=cnt[v],pos=v; 36 } 37 cnt[pos]--; cut[u][pos]=cut[pos][u]=1; 38 } 39 void DFS(int u) 40 { 41 dfn[u]=++tim; 42 for(int v,i=head[u]; i; i=edge[i].next) 43 { 44 v=edge[i].v; 45 if(!cut[u][v]&&!cut[v][u]&&!dfn[v]) DFS(v); 46 } 47 } 48 49 int Presist() 50 { 51 // freopen("c.in","r",stdin); 52 // freopen("c.out","w",stdout); 53 read(n); 54 for(int u,v,i=1; i<n; ++i) 55 read(u),read(v),ins(u,v); 56 for(int i=1; i<=n; ++i) 57 for(; cnt[i]>2; cnt[i]--) 58 Cutedge(i),ans++; 59 for(int i=1; i<=n; ++i) 60 if(!dfn[i]) DFS(i),ans++; 61 printf("%d ",ans); 62 return 0; 63 } 64 65 int Aptal=Presist(); 66 int main(int argc,char**argv){;}
贪心处理每个节点,当一个点的度数>2时,一定需要删去一条父边,这个点对答案的贡献是 cnt[i]-2<<1,
要求是一条链,所以多出的边都应删去,一个环的总边数不变,删去的边一定会在累加上,所以*2
1 #include <cstdio> 2 3 inline void read(int &x) 4 { 5 x=0; register char ch=getchar(); 6 for(; ch>'9'||ch<'0'; ) ch=getchar(); 7 for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0'; 8 } 9 10 const int N(100005); 11 12 int n,cnt[N],ans; 13 int head[N],sumedge; 14 struct Edge { 15 int v,next; 16 Edge(int v=0,int next=0):v(v),next(next){} 17 }edge[N<<1]; 18 inline void ins(int u,int v) 19 { 20 cnt[u]++; cnt[v]++; 21 edge[++sumedge]=Edge(v,head[u]); head[u]=sumedge; 22 edge[++sumedge]=Edge(u,head[v]); head[v]=sumedge; 23 } 24 25 void DFS(int u,int pre) 26 { 27 for(int v,i=head[u]; i; i=edge[i].next) 28 { 29 v=edge[i].v; 30 if(v==pre) continue; 31 DFS(v,u); 32 if(cnt[v]>2) 33 { 34 cnt[u]--; 35 ans+=cnt[v]-2<<1; 36 } 37 } 38 } 39 40 int Presist() 41 { 42 freopen("c.in","r",stdin); 43 freopen("c.out","w",stdout); 44 read(n); 45 for(int u,v,i=1; i<n; ++i) 46 read(u),read(v),ins(u,v); 47 for(int i=1; i<=n; ++i) 48 if(cnt[i]==1) { DFS(i,0); break; } 49 printf("%d ",ans+1); 50 return 0; 51 } 52 53 int Aptal=Presist(); 54 int main(int argc,char**argv){;}