赤色の部分が重要箇所を示している.
繰り返しの各回ごとに出力を行うのだから, printf はループの中に置く.int main(void){ char buf[80]; int j; int i; int k; gets(buf); j = atoi(buf); printf("%d\n", j); for(i=1; i<=j; i++){ k = j % i; printf("%d mod %d -> %d\n", j, i, k); } }
int main(void){ char buf[80]; int j; int i; int k; gets(buf); j = atoi(buf); printf("%d\n", j); for(i=1; i<=j; i++){ k = j % i; if(k == 0){ printf("%d\n", i); } } }
int main(void){ char buf[80]; int j; int i; int k; int n; gets(buf); j = atoi(buf); printf("%d\n", j); n = 0; for(i=1; i<=j; i++){ k = j % i; if(k == 0){ n = n + 1; } } printf("%d\n", n); }
int main(void){ char buf[80]; int j; int i; int k; int n; gets(buf); j = atoi(buf); printf("%d\n", j); n = 0; for(i=1; i<=j; i++){ k = j % i; if(k == 0){ n = n + 1; } } if(n == 2){ printf("prime\n"); } else { printf("not prime\n"); } }
前の問題同様, 段階的に考えてみる.
等差数列の和の公式を使ってsumを一気に計算するなら, 赤色の部分はint main(void){ char line[80]; int i,j, sum; int k; gets(line); i = atoi(line); printf("%d\n", i); gets(line); j = atoi(line); printf("%d\n", j); sum = 0; for(k=i; k<=j; k++){ sum = sum + k; } printf("%d + ... + %d = %d\n", i, j, sum); }
とすればよい. (そしてこちらの方が繰り返しがないぶん高速)sum = (i+j)*(j-i+1)/2;
合計の計算は等差数列の和の公式を使うことにした.int main(void){ char line[80]; int i,j, sum; gets(line); j = atoi(line); printf("%d\n", j); for(i=1; i<j; i++){ sum = (i+j)*(j-i+1)/2; printf("%d + ... + %d = %d\n", i, j, sum); } }
外側のループでは j は 1 から max_j まで変化し, 内側では外側の j がひとつきまったときに i を 1 から (j-1) まで変化させる. つまり, 内側のループをまわる回数は毎回異なる. (j が 1 のときは0回, j が 2 のときは1回, … というぐあい)int main(void){ char line[80]; int i,j, sum; int max_j; gets(line); max_j = atoi(line); printf("%d\n", max_j); for(j=1; j<=max_j; j++){ for(i=1; i<j; i++){ sum = (i+j)*(j-i+1)/2; printf("%d + ... + %d = %d\n", i, j, sum); } } }
int main(void){ char line[80]; int i,j, sum; int n; gets(line); n = atoi(line); printf("%d\n", n); for(j=1; j<=n; j++){ for(i=1; i<j; i++){ sum = (i+j)*(j-i+1)/2; if(n == sum){ printf("%d + ... + %d = %d\n", i, j, sum); } } } }
点(x,y)と原点との距離を求めるには平方根の計算が必要となるが, 平方根をとらなくても
x*x + y*y <= n*nで等価な条件となる.
対象となる格子点は, x, y についての二重ループで すべてを訪問できる. この場合, 繰り返しの範囲が -n から n までとなることに注意.
#include <stdio.h> main(){ int n, x, y, z, c; char line[256]; gets(line); n = atoi(line); printf("%d\n", n); c = 0; for(y = -n; y <= n; y++){ for(x = -n; x <= n; x++){ z = x*x + y*y; if(z <= n*n){ c++; } } } printf("%d\n", c); }
この問題で, 円内の格子点の個数をいきなり n の多項式などで もとめようとがんばっていた人が多かったけれど, 上のプログラムのように点ひとつずつ地道に調べるのが早道.また, 別解として x をひとつ決めたときに y = 「(n*n - x*x)の平方根の整数部」とすると その x での格子点の個数は y*2+1 となる. プログラムはこんな感じ:なお, 問題にもあったとおり「(格子点の数)/(n*n)」 は πに収束するはずであるから, そのような格子点の個数を整数係数の n の多項式では 表現できないのではないかと思う.
ここで, isqrtというのが, 平方根の整数部を求める関数である. 関数についての説明はつぎの授業で!#include <stdio.h> int isqrt(int i){ int r = 0; while(r*r <= i){ r++; } // rがiの平方根を越えたところでループ終了 // したがって,iの平方根の整数部は(r-1) return (r-1); } int main(){ int n, x, y; int c; char line[256]; gets(line); n = atoi(line); printf("%d\n", n); c = 0; for(x=-n; x<=n; x++){ y = isqrt(n*n - x*x); c += y * 2 + 1; } printf("%d\n", c); }