2016.8.12
【背景】
为了迎接即将到来的NOIP2016,我决定爆刷CodeVS的天梯,今天爆刷了11道白银的水题。其实说是水题,有些还挺有意思的,比如1012、1011。
【题解】
> 1011 数的计算
- f[i]表示输入i时应该输出的答案,易得f[i]=∑f[j]( j=1 to (i div 2) ),这样是 O(N^2)的,可以维护一个f的前缀和s[i],转移变为f[i]=s[i div 2],复杂度O(N)
(PS:后来我出了一道题,就是这道题的升级版,link:wyw的数字金字塔)
//CodeVS 1011 数的计算 2001年NOIP全国联赛普及组
#include
using namespace std;
int n, f[1010], s[1010];
int main()
{
int i, j;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
f[i]=s[i>>1]+1;
s[i]=s[i-1]+f[i];
}
printf("%d",f[n]);
return 0;
}
> 1012 最大公约数和最小公倍数问题
- 我对数论不敏感。。。所以这道做着有点困难。可以推出题目的等价问题是找无序整 数对(a,b)使得gcd(a,b)=1 且 lcm(a,b)=y0/x0,就是说a和b必须互质且最小公倍数为,那么将t分解质因数t=p1^q1*p2^q2*...*pm^qm,假如a有了里面的一个质因子pi,那么b必须没有这个质因子,且a中这个质因子的指数必须和t中这个质因子的指数相等,只有这样才能同时满足上述条件,同样的b有这个质因子时所有情况相反。也就是说对于任何一个t的质因子pi,且指数为qi。则要么a含有pi的qi次幂,bi中不含有pi;要么a不含pi,b含有pi的qi次幂。对于任何一个pi,都有这两种情况,假如t共有m个质因子,则由乘法原理可知(也可以从二进制的角度来理解),答案就为2^m。综上所述,对t进行质因数分解,分解出m个质因子,答案即为2^m。
(PS:后来在一次模拟赛中,我出了道类似的题目:wyw的诅咒)
//CodeVS 1012 最大公约数和最小公倍数问题 2001年NOIP全国联赛普及组 数论
#include
using namespace std;
int main()
{
int x0, y0, t, ans=1, x;
scanf("%d%d",&x0,&y0);
if(y0%x0)
{
printf("0\n");
return 0;
}
for(x=2,t=y0/x0;t>1;x++)
{
if(t%x==0)ans<<=1;
while(t%x==0)t/=x;
}
printf("%d\n",ans);
return 0;
}
> 1083 Cantor表
- 把题目中的那张图顺时针旋转45°,可以得到一个金字塔形的东西。不难看出有性质:第i行共有i个数,且第j个数是第i-j+1个数的倒数(j<=i)奇数排从左往右数,偶数排从右往左数,所以我们干脆就全都从左往右数,对于偶数排,直接把求出的答案变成倒数即可。用等差数列求和公式∑(1 to i)=i(i+1)/2,枚举i找到最小的i使得∑(1 to i)>=N,则要求的数就是第i行的第(N-i(i-1)/2)个数,对于奇数排,答案就是(i+1-N)/N,偶数排取倒数即可。
//CodeVS1083 NOIP1999 Cantor表 水题模拟
#include
using namespace std;
int main()
{
int i, N, a, b;
scanf("%d",&N);
for(i=1;(i*(1+i)>>1)>1);
b=N;a=i+1-b;
if(i&1)printf("%d/%d\n",a,b);
else printf("%d/%d\n",b,a);
return 0;
}
> 1160 蛇形矩阵
- 水题模拟不解释
//CodeVS 1160 蛇形矩阵 水题模拟
#include
using namespace std;
int matrix[110][110];
int main()
{
int N, i, j, cnt, sigma, l, r, u, d;
scanf("%d",&N);
cnt=N*N;
for(i=1;i<=N;i++)matrix[0][i]=matrix[N+1][i]=matrix[i][0]=matrix[i][N+1]=1;
i=N;j=N;matrix[N][N]=cnt--;
while(i!=(N+1>>1)||j!=(N+1>>1))
{
l=matrix[i][j-1];
r=matrix[i][j+1];
u=matrix[i-1][j];
d=matrix[i+1][j];
if(!d&&!r)j++;
else if(!l&&!d)i++;
else if(!l&&!u)j--;
else if(!u&&!r)i--;
else if(!d)i++;
else if(!l)j--;
else if(!u)i--;
else if(!r)j++;
matrix[i][j]=cnt--;
}
for(i=1,sigma=0;i<=N;i++)sigma+=matrix[i][i]+matrix[i][N-i+1];
for(i=1;i<=N;i++)
{
for(j=1;j<=N;j++)printf("%d ",matrix[i][j]);
printf("\n");
}
printf("%d\n",sigma-1);
return 0;
}
> 1430 素数判定
- 最基本的根号n的素数判定
//CodeVS 1430 素数判定 水题
#include
using namespace std;
int main()
{
int x, t, n;
scanf("%d",&n);
for(x=2;x*x<=n&&n%x;x++);
if(x*x<=n)printf("\\n\n");
else printf("\\t\n");
return 0;
}
> 1474 十进制转m进制
- 小学生题。。
//CodeVS 1474 十进制转m进制 水题
#include
using namespace std;
int stack[1000], top;
int main()
{
int n, m;
scanf("%d%d",&n,&m);
while(n)
{
stack[++top]=n%m;
n/=m;
}
while(top)
if(stack[top]>=10)printf("%c",stack[top--]-10+'A');
else printf("%c",stack[top--]+'0');
printf("\n");
return 0;
}
> 1475 m进制转十进制
- 同上
//CodeVS 1475 m进制转十进制 水题
#include
#include
using namespace std;
int ans, m;
char s[10000];
int main()
{
int i, x, t;
scanf("%s%d",s,&m);
for(i=strlen(s)-1,x=1;i>=0;i--,x*=m)
{
if(s[i]>='A')t=s[i]-'A'+10;
else t=s[i]-'0';
ans+=t*x;
}
printf("%d\n",ans);
return 0;
}
> 1501 二叉树最大宽度和高度
- 浪费生命的题,必须5分钟A掉
//CodeVS1501 二叉树最大宽度和高度 水题搜索
#include
#include
using namespace std;
int cnt[20], n, maxdep, l[20], r[20], maxlen;
void dfs(int p, int dep)
{
cnt[dep]++;
if(l[p])dfs(l[p],dep+1);
if(r[p])dfs(r[p],dep+1);
maxdep=max(maxdep,dep);
}
int main()
{
int i;
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d%d",&l[i],&r[i]);
dfs(1,1);
maxlen=0;
for(i=1;i<=maxdep;i++)if(cnt[i]>maxlen)maxlen=cnt[i];
printf("%d %d\n",maxlen,maxdep);
return 0;
}
> 1842 递归第一次
- 虽然让用递归,但是根本没必要啊。。这道题连数组都不用
//CodeVS1842 递归第一次 水题
#include
using namespace std;
int main()
{
int x, a, b, t;
scanf("%d",&x);
if(x>=0){printf("5\n");return 0;}
x=-x;
a=b=5;
while(x--)t=a+b+1,a=b,b=t;
printf("%d\n",b);
return 0;
}
> 3038 3n+1问题
- 题目说“至今没有人证明对所有的正整数该过程都终止”,也就是说至今也没有发现哪个数无法终止,所以就不用考虑输出-1的情况了。直接写一个递归发现每个数终止的步数还是挺少的。
//CodeVS 3038 3n+1问题 水题
#include
#include
using namespace std;
int dfs(int x)
{
if(x==1)return 0;
if(x&1)return dfs(3*x+1)+1;
return dfs(x>>1)+1;
}
int main()
{
int T, n, i, t;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
printf("%d\n",dfs(n));
}
return 0;
}
> 3143 二叉树的序遍历
- 水题
//CodeVS 3143 二叉树的序遍历 水题
#include
using namespace std;
int n, l[100], r[100], tot, s1[100], s2[100], s3[100];
void dfs(int x)
{
s1[++s1[0]]=x;
if(l[x])dfs(l[x]);
s2[++s2[0]]=x;
if(r[x])dfs(r[x]);
s3[++s3[0]]=x;
}
int main()
{
int i;
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d%d",&l[i],&r[i]);
dfs(1);
for(i=1;i<=n;i++)printf("%d ",s1[i]);printf("\n");
for(i=1;i<=n;i++)printf("%d ",s2[i]);printf("\n");
for(i=1;i<=n;i++)printf("%d ",s3[i]);printf("\n");
return 0;
}