Hdu 5752 Sqrt Bo
链接
Sqrt Bo
题意
$f(n)=\lfloor \sqrt{n}\rfloor,f^1(n)=f(n),f^y(n)=f(f^{y-1}(n))$
每计算一次函数f需一个单位时间,给定一个数n,问需要几个单位时间使得$f^y(n)=1$.若需超过5个单位时间输出”TAT”.
分析
由于有5次的这个限制,所以尝试寻找分界点。很容易发现是$2^{32}$,所以我们先比较输入的数字是否比这个大,然后再暴力开根复杂度是$O(\log\log n)$.注意n=0答案为0。
参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include<stdio.h> #include<string.h> #include<math.h> int main() { char str[150]; while(scanf("%s",str)!=EOF){ int n=strlen(str); if(n>15||(str[0]=='0'&&n==1)){ printf("TAT\n"); continue; } long long num=0; for(int i=0;i<n;i++){ num=num*10+str[i]-'0'; } int ans=0; while(num!=1){ num=floor(sqrt(num*1.0)); ans++; } if(ans>5) printf("TAT\n"); else printf("%d\n",ans); } return 0; }
|
Hdu 5753 Permutation Bo
链接
Permutation Bo
题意
$h_1\sim h_n$是$1\sim n$的排列,$h_0=h_{n+1}=0,f(h)=\sum_{i=1}^{n}{c_i[h_i>h_{i-1} and h_i>h_{i+1}]}$
已知 $c_1\sim c_n$,求 f(h)的期望
分析
根据期望的线性性,我们可以分开考虑每个位置对答案的贡献。
1)i在两端,对答案贡献为 ci/3
2)i不在两边,对答案贡献为ci/2
参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #include<stdio.h> #include<string.h> int c[1010]; int main() { int n; while(scanf("%d",&n)!=EOF){ double sum=0; for(int i=1;i<=n;i++){ scanf("%d",&c[i]); } if(n==1){ printf("%d\n",c[1]); continue; } for(int i=1;i<=n;i++){ if(i==1||i==n) sum+=c[i]/2.0; else sum+=c[i]/3.0; } printf("%lf\n",sum); } return 0; }
|
Hdu 5754 Life Winner Bo
链接
Life Winner Bo
题意
一个国际象棋棋盘,有四种棋子,要从(1,1)走到(n,m),两人轮流下棋,每次只能往右下方向走,先走到(n,m)的人赢,先手赢输出B,后手赢输出G,平局输出D。
分析
四种棋子的规则如下:
1、王(King):横、竖、斜都可以走,每次限走一格,
若(n-1)和(m-1)都为偶数,先手必败,也可用SG函数处理
2、车(Rook):横、竖均可走,不能斜走,格数不受限制,可以看成有两堆石子的尼姆博弈
3、马(Knight):马走日,可用SG函数处理
4、后(Queen):横、竖、斜都可以走,格数不受限制,可看成威佐夫博弈
参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| #include<stdio.h> #include<string.h> #include<math.h> #define N 1005 int n,m,sg_king[N][N],sg_knight[N][N]; void king() { memset(sg_king,-1,sizeof(sg_king)); sg_king[1][1]=0; for(int i=1;i<N;i++){ for(int j=1;j<N;j++){ if(sg_king[i-1][j]&&sg_king[i][j-1]&&sg_king[i-1][j-1]) sg_king[i][j]=0; else sg_king[i][j]=1; } } } void knight() { memset(sg_knight,-1,sizeof(sg_knight)); sg_knight[1][1]=0; for(int i=1;i<=1000;i++){ for(int j=1;j<=1000;j++){ int x=-1,y=-1; if(i-2>=1&&j-1>=1) x=sg_knight[i-2][j-1]; if(i-1>=1&&j-2>=1) y=sg_knight[i-1][j-2]; if(x==0||y==0) sg_knight[i][j]=1; else if(x==1&&y==1) sg_knight[i][j]=0; } } } int main() { int T; king(); knight(); scanf("%d",&T); while(T--){ int type; scanf("%d%d%d",&type,&n,&m); if(type==1){ if(sg_king[n][m]) printf("B\n"); else printf("G\n"); } else if(type==2){ int res=(n-1)^(m-1); if(res) printf("B\n"); else printf("G\n"); } else if(type==3){ if(sg_knight[n][m]==-1) printf("D\n"); else if(sg_knight[n][m]==0) printf("G\n"); else printf("B\n"); } else if(type==4){ int a=n-1,b=m-1; if(a>b){ a=a^b; b=a^b; a=a^b; } int res=floor((b-a)*(1+sqrt(5.0))/2.0); if(res==a) printf("G\n"); else printf("B\n"); } } return 0; }
|
Hdu 5755 Gambler Bo
链接
Gambler Bo
题意
给定一个只含{0,1,2}的n*m的矩阵。有一种操作:将(x,y)位置+2,
同时(x-1,y),(x+1,y),(x,y-1),(x,y+1)都会+1,若格子的值超过3,则需模3。
要求进行不超过2*n*m次操作将矩阵变为全0,数据保证至少有一组解。
分析
问题可以转化为一个模3域下的方程,对每个位置可以列出一个方程,
即覆盖到这个位置的操作造成的影响和要使得这个位置变为0。
对于同一格,操作三次后又会回到为操作前的状态,即每个格最多操作两次,总次数不超过2*n*m
列出同余方程组后,进行高斯消元,涉及到除法的地方需要求逆元。
参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
| #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define mod 3 const int N=1000; int a[N][N],ans[N],sum; const int dx[4]={0,0,1,-1}; const int dy[4]={1,-1,0,0}; int gcd(int a,int b) { return b==0?a:gcd(b,a%b); } int Lcm(int a,int b) { return a/gcd(a,b)*b; } int gauss(int n,int m) { int row=0,col=0; for(;row<n;row++,col++){ int notZero=row; for(int i=row;i<n;i++) if(a[i][col]){ notZero=i; break; } if(notZero==n){ row--; continue; } if(notZero!=row){ for(int j=0;j<=m;j++) swap(a[row][j],a[notZero][j]); } for(int i=row+1;i<n;i++){ if(a[i][col]){ int lcm=Lcm(a[row][col],a[i][col]); int t1=lcm/a[row][col]; int t2=lcm/a[i][col]; for(int j=col;j<=m;j++) a[i][j]=((a[i][j]*t1-a[row][j]*t2)%mod+mod)%mod; } } } memset(ans,0,sizeof(ans)); sum=0; for(int i=n-1;i>=0;i--){ if(a[i][i]==0) continue; int temp=a[i][m]; for(int j=i+1;j<m;j++){ temp=((temp-a[i][j]*ans[j])%mod+mod)%mod; } ans[i]=temp*a[i][i]%mod; sum+=ans[i]; } return 0; } int main() { int T; scanf("%d",&T); while(T--){ int n,m; scanf("%d%d",&n,&m); memset(a,0,sizeof(a)); for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ int x; scanf("%d",&x); a[i*m+j][i*m+j]=2; a[i*m+j][n*m]=(-x+mod)%mod; for(int k=0;k<4;k++){ int r=i+dx[k]; int c=j+dy[k]; if(r>=0&&r<n&&c>=0&&c<m) a[i*m+j][r*m+c]=1; } } } gauss(n*m,n*m); printf("%d\n",sum); for(int i=0;i<n*m;i++){ int r=i/m+1; int c=i%m+1; for(int j=0;j<ans[i];j++) printf("%d %d\n",r,c); } } return 0; }
|
Hdu 5761 Rower Bo
链接
Rower Bo
题意
有一条沿水平方向的河,Bo在(0,a)点,他想到源点(0,0),已知静水中速度v1,水流速v2,
v1的方向一直朝向原点,求需要多就到达,若到不了输出”Infinity”
分析
官方题解推导如下:
参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include<stdio.h> int main() { int a,v1,v2; while(scanf("%d%d%d",&a,&v1,&v2)!=EOF){ if(a==0) printf("0\n"); else if(v1<=v2) printf("Infinity\n"); else{ double ans=(double)a*v1/(v1*v1-v2*v2); printf("%lf\n",ans); } } return 0; }
|
Hdu 5762 Teacher Bo
链接
Teacher Bo
题意
已知n个点,求是否存在(A,B,C,D)满足A和B的曼哈顿距离跟C和D的曼哈顿距离相等.
其中A与B点不能为统一点,C与D不能为统一点,B和C可为同一点
A(x1,y1),B(x2,y2),AB的曼哈顿距离=|x1-x2|+|y1-y2|
分析
考虑一种暴力,每次枚举两两点对之间的曼哈顿距离,并记录每种距离是否出现过,
如果某次枚举出现了以前出现的距离就输 YES,否则就输 NO.
注意到曼哈顿距离只有 O(M)种,根据鸽笼原理,上面的算法在 O(M)步之内一定会停止.
一组数据的时间复杂度 $O(\min{N^2,M})$
参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int N=100010; struct point{ int x,y; }p[N]; bool vis[N<<1]; int main() { int T; scanf("%d",&T); while(T--){ int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d%d",&p[i].x,&p[i].y); } memset(vis,false,sizeof(vis)); bool flag=false; for(int i=1;i<=n&&!flag;i++){ for(int j=i+1;j<=n;j++){ int d=abs(p[i].x-p[j].x)+abs(p[i].y-p[j].y); if(!vis[d]) vis[d]=true; else{ flag=true; break; } } } if(flag) printf("YES\n"); else printf("NO\n"); } return 0; }
|