Problem D: TomCat要吃饭
Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 117 Solved: 52
[Submit][Status][Web Board]
Description
TomCat 是一次单身Cat,但是他有着很多的基友,每次吃饭都会QQ他的某一只基友,然而,他的基友Jerry 总是很墨迹。等待是无聊的,这时TomCat在学校的地上乱走,这时他发现地上有方块铺成的,他按照下图的规律走,现在无聊的TomCat想知道,他如果走了n步,他应该在什么位置,位置用坐标(x,y)表示。
Input
每次输入一个数n,n=0是输入结束(n<=2*10^9)
Output
输出坐标(x,y)
Sample Input
8
20
25
0
Sample Output
2 3
5 4
1 5
题目大意:
找规律给你个数,输出他的坐标。
思路:
首先是要确定数所在的行数(数外面围的一圈算一行),因为每一行的增长方式不同 偶数行先右再下,奇数行先上后左。
接下来观察每一行的端点(最大值),发现刚好是行数的平方,所以我们只需把输入的数开根号+1就是数所在的行数了。要是刚好是端点就不用+1了。
光这样还不够,还得知道何时转弯,就要算出转折点是多少,再看转折点,发现是2,4,6.。。。递增的,由此推出计算公式a*a-a+2(a为行数)。以转折点为基准判断是x变还是y变。
AC代码:
#include<stdio.h>
#include <math.h>
int main()
{
long n,i,p;
while (1)
{
scanf("%ld",&n);
if(n==0)
break;
p=0;
i=sqrt(n);
if(i*i!=n)
i++;
// printf("%d\n",i);
if(i%2==0)
{
if(n>i*i-i+1)
printf("%d %d\n",i,i-n+i*i-i+1);
else
if(n<i*i-i+1)
printf("%d %d\n",i-(i*i-i+1)+n,i);
else
printf("%d %d\n",i,i);
}
else
{
if(n<i*i-i+1)
printf("%d %d\n",i,i-(i*i-i+1)+n);
else
if(n>i*i-i+1)
printf("%d %d\n",i-n+i*i-i+1,i);
else
printf("%d %d\n",i,i);
}
}
}
Problem H: 阶乘的零
Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 338 Solved: 67
[Submit][Status][Web Board]
Description
定义f(n)为n!的末尾零的个数,例如f(4)=0,f(5)=1。你的任务是对于一个给定的的值x找出最小的n满足f(n)=x。
Input
多组测试数据,每组测试数据包含一个正整数x(1<=x<=10^8)。
Output
对于每组测试数据输出对应的n,若没有n满足则输出“No solution”。
Sample Input
2
Sample Output
10
思路:
主要有两个问题,怎么计算阶乘的零的个数,和怎么最快找出最小的n满足f(n)=x。
对于第一个问题,我们思考一下什么时候会加0,明显只有5*2=10才会加零,而2的数量明显绰绰有余,所以数有几个5就有几个0了,注意5加一个0, 25加2个0, 125加3个0,以此类推。
实现代码:
ll f(ll x)//计算有几个0
{
ll sum = 0, b = 5;
while (b <= x)
{
sum += x / b;
b *= 5;
}
return sum;
}
对于快速查找,可以使用二分查找,但我用的是个比较奇葩的方法,从x*4开始找,x为0的个数。也说不出什么科学道理,实践出来的规律,还真有用!
AC代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<set>
#include<cmath>
typedef long long ll;
using namespace std;
typedef long long ll;
using namespace std;
ll f(ll x)
{
ll sum = 0, b = 5;
while (b <= x)
{
sum += x / b;
b *= 5;
}
return sum;
}
int main()
{
ll n, c, a, b;
ll x, y = 0;
while (scanf("%lld", &n) != EOF&&n)
{
// cout<<f(n)<<endl;
y = 0;
for (ll i = n * 4;; i++)
{
if (f(i) == n)
{
y = 1;
cout << i << endl;
break;
}
if (f(i)>n)
break;
}
if (!y)
{
cout << "No solution\n";
}
}
return 0;
}
Problem I: 工程
Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 222 Solved: 118
[Submit][Status][Web Board]
Description
某省自从实行了很多年的畅通工程计划后,终于修建了很多路。不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行走的距离要短很多。这让行人很困扰。
现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离。
Input
本题目包含多组数据,请处理到文件结束。
每组数据第一行包含两个正整数N和M(0<N<200,0<M<1000),分别代表现有城镇的数目和已修建的道路的数目。城镇分别以0~N-1编号。
接下来是M行道路信息。每一行有三个整数A,B,X(0<=A,B<N,A!=B,0<X<10000),表示城镇A和城镇B之间有一条长度为X的双向道路。
再接下一行有两个整数S,T(0<=S,T<N),分别代表起点和终点。
Output
对于每组数据,请在一行里输出最短需要行走的距离。如果不存在从S到T的路线,就输出-1.
Sample Input
3 3
0 1 1
0 2 3
1 2 1
0 2
3 1
0 1 1
1 2
Sample Output
2
-1
题目大意:
算图的最短路径
思路:
Floyd算法
核心代码
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(f[i][j]>f[i][k]+f[k][j])
f[i][j]=f[i][k]+f[k][j];
AC代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<set>
#include<cmath>
typedef long long ll;
using namespace std;
int main()
{
int n,m;
int f[205][205];
while(scanf("%d %d",&n,&m) != EOF){
int a,b,c;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(i==j)
f[i][j]=0;
else
f[i][j]=999999;
for(int i=0;i<m;i++)
{
cin>>a>>b>>c;
f[a][b]=f[b][a]=c;
}
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(f[i][j]>f[i][k]+f[k][j])
f[i][j]=f[i][k]+f[k][j];
cin>>a>>b;
if(f[a][b]==999999)
cout<<"-1"<<endl;
else
cout<<f[a][b]<<endl;
}
return 0;
}
Problem J: 第K完美序列
Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 202 Solved: 108
[Submit][Status][Web Board]
Description
有一个由n个数字组成的序列,序列的每个数字不是1就是2。如果一个序列是第K完美序列,则这个序列满足以下两点;
1.k是n的因子。
2.这个序列中每隔k个元素都相等。
例如序列(1,2,1,2,1,2,1,2),不仅是一个第2完美序列而且又是一个第4完美序列。序列(1,1,1,1)是一个第1完美序列。
你的任务是给定一个由n个数字组成的序列,最少需要改变几个元素才能使这个序列变成一个第K完美序列。
Input
多组测试数据。
每组测试数据的第一行为两个正整数n,k(1<=k<=n<=100)。
第二行为n个由空格分隔的正整数代表这个序列。
Output
对于每组测试数据,输出最少需要改变的次数。
Sample Input
6 2
2 1 2 2 2 1
8 4
1 1 2 1 1 1 2 1
9 3
2 1 1 1 2 1 1 1 2
Sample Output
1
0
3
题目大意:
将数列分成k份,改变最少次数使子序列相等。
思路:
不要用n的数组存,用长度为n/k的数组存k次,把每个位置上1和2的个数记录下来,选少的那个,再把n/k个位置上所有的数加起来就是最少操作次数。
AC代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<set>
#include<cmath>
typedef long long ll;
using namespace std;
int main()
{
ll n,c[105][105],a,b;
ll x,y=0;
while(scanf("%lld %lld",&n,&a)!=EOF)
{
b=n/a;
memset(c,0,sizeof(c));
for(int i=0;i<b;i++)
{
for(int j=0;j<a;j++)
{
scanf("%d",&x);
if(x%2==0)
{
c[j][2]++;
}
else
c[j][1]++;
}
}
ll sum=0;
for(int i=0;i<a;i++)
{
// cout<<c[i]<<endl;
sum+=min(c[i][2],c[i][1]);//1和2个数少的那个加起来
}
cout<<sum<<endl;
}
return 0;
}