問題はこちら
No.513 宝探し2 - yukicoder
制約の厳しいバージョンと全く同じなので詳細はそちら
yukicoder No.514 宝探し3 - メモ
a,b;main(i){for(;i%2^!a^!b&&fflush(!printf("%d %d\n",a-b/2,b/2))+scanf("%d",&b+i++%2););}
89B
問題はこちら
No.513 宝探し2 - yukicoder
制約の厳しいバージョンと全く同じなので詳細はそちら
yukicoder No.514 宝探し3 - メモ
a,b;main(i){for(;i%2^!a^!b&&fflush(!printf("%d %d\n",a-b/2,b/2))+scanf("%d",&b+i++%2););}
89B
問題はこちら
No.514 宝探し3 - yukicoder
N=100000とおく
(0,0)及び(N,0)の2点からの距離が分かれば特定できる。
なぜなら、それぞれの点からの距離をd1,d2、宝の位置を(x,y)とすれば
x+y=d1
(N-x)+y=d2
となるので、この連立方程式を解く事により
x=(d1-d2+N)/2
y=(d1+d2-N)/2
が得られるからである。
これをそのまま実装する
x,y,d1,d2,N=100000; main(){ printf("0 0\n"); scanf("%d",&d1); if(d1==0)return 0; printf("100000 0\n"); scanf("%d",&d2); if(d1==2)return 0; printf("%d %d\n",(d1-d2+N)/2,(d1+d2-N)/2); }
よく考えると、2回目に質問する座標は(d1,0)でもよいことがわかる(宝の位置が質問する点より左にありさえすれば、(N,0)と同じ式が得られるので)
このことに注意しつつ、あとでループの形にできるように、同じような形になるよう書き換えたのがこれ
a,b; main(){ fflush(!printf("%d %d\n",a-b/2,b/2));scanf("%d",&a); if(a)fflush(!printf("%d %d\n",a-b/2,b/2)),scanf("%d",&b); if(b)fflush(!printf("%d %d\n",a-b/2,b/2)); }
ループ変数iはmainの引数に入れたいので、1から始まることを考えると
(i,a,b)が(1,0,0),(2,非0,0),(3,非0,非0)の時だけscanfをし、(2,0,0),(3,非0,0)のときはscanfを実行しないように分岐したい。
これはぐっと睨むとi%2^!a^!bと書けることがわかるので次のように書ける
a,b;main(i){for(;i%2^!a^!b&&fflush(!printf("%d %d\n",a-b/2,b/2))+scanf("%d",i++%2?&a:&b););}
ここでa,bのアドレスを調べると、b,aの順に並んでいることがわかるので、scanfの引数の分岐をまとめることができる
a,b;main(i){for(;i%2^!a^!b&&fflush(!printf("%d %d\n",a-b/2,b/2))+scanf("%d",&b+i++%2););}
89B
問題はこちら
No.516 赤と青の風船 - yukicoder
入力を読み込んで、それがBLUEかREDか判別する
char s[10]; b,r; main(){ for(int i=0;i<3;i++){ scanf("%s",s); if(strcmp(s,"BLUE")==0)b++; else r++; } if(b<r)puts("RED"); else puts("BLUE"); }
各文字列の長さが短いのでint型に読み込んでも大丈夫そう。
文字数が違うので、BLUEとREDをint型として見た時の値の大きさは大きく異なり、例えばこういうのが考えられる
s; main(i){ for(;gets(&i);s+=i>>30); puts(s>1?"BLUE":"RED"); }
ただ、もっとよく考えると、BLUEがINT_MAX/2より僅かに大きいことを利用して次のようにできる
s; main(i){ for(;gets(&i);s+=i); puts(s<0?"BLUE":"RED"); }
54B
問題はこちら
No.512 魔法少女の追いかけっこ - yukicoder
追いかける側がA[i]地点にあるi番目の交差点にたどり着いた時、追いかけられる側はA[i]/X*Y地点にいる。これがA[i+1]より真に大きければ見失う。
除算をすると誤差で落とされるケースが多数あるらしいので、A[i]/X*Y≦A[i+1]をA[i]*Y≦A[i+1]*Xと変形して整数の範囲でやる
a[100],x,y,n; main(){ scanf("%d%d%d",&x,&y,&n); for(int i=0;i<n;i++)scanf("%d",a+i); for(int i=0;i<n-1;i++)if(a[i]*y>a[i+1]*x){ puts("NO"); return 0; } puts("YES"); }
前から順番に読み込めば配列はいらない
p,q,f; main(a,b){ for(scanf("%d%d%*d",&a,&b);~scanf("%d",&q);p=q)f|=a*q<b*p; puts(f?"NO":"YES"); }
94B
scanfを1つにするパターンも考えたが、Nの読み飛ばしが難しくて短くならなかった
p,q,f;main(a,b){for(scanf("%d%d%*d",&a,&b);~scanf("%d",&q);p=q)f|=a*q<b*p;puts(f?"NO":"YES");} a,b,p,q,f;main(i){for(;~scanf("%d",&q);*(--i?~i?i+2?&p:&q:&b:&a)=q)f|=a*q<b*p;puts(f?"NO":"YES");} a,b,p,q,f;main(i){for(;~scanf("%d",&q);~i--?i>-2?a=b,b=q:(p=q):0)f|=a*q<b*p;puts(f?"NO":"YES");}
2017/08/01追記
やっぱりscanfを1つにしたほうが短くなった
a,b,p,q,f; main(i){ for(;~scanf("%d",a?b?&q:&b:&a);--i+2?p=q:0)f|=a*q<b*p; puts(f?"NO":"YES"); }
92B
問題はこちら
No.509 塗りつぶしツール - yukicoder
また、白でも黒でもない3つ目の色を赤と呼ぶことにする。
領域を「背景」「文字」「穴」の3つの領域に呼び分ける。
背景を塗りつぶすのは1回、文字をすべて塗りつぶすには文字数回、穴をすべて塗りつぶすには穴の個数回の操作が必要。
・背景を1回だけ塗りつぶす場合
背景の色は「白→黒」と変更されるので、そのとき文字の色は赤になっていなければならない。
すなわち各文字の色は2回以上変更されるので、全体では最低でも2*(文字数)+(穴数+1)回の操作が必要。
実際に「文字をすべて赤にする→背景と穴をすべて黒にする→文字をすべて白にする」という手順で最小回数を達成できる
・文字を1回だけ塗りつぶす場合
文字の色は「黒→白」と変更されるので、そのとき背景及び穴の色は赤になっていなければならない。
すなわち背景及び穴の色は2回以上変更されるので、全体では最低でも2*(穴数+1)+文字数回の操作が必要。
実際に「背景と穴をすべて赤にする→文字をすべて白にする→背景と穴をすべて黒にする」という手順で最小回数を達成できる
・背景,文字をどちらも2回以上塗りつぶす場合
最低でも2*(文字数)+(穴数)+2回の変更が必要なのでこれは1番目のパターンより必ず回数が多くなる
ということで、結局min{2*(文字数)+(穴数+1),2*(穴数+1)+文字数}が答えになることがわかる。
#define min(p,q)(p<q?p:q) a[]={1,0,0,0,1,0,1,0,2,1}; s,h,x; main(){ while(1){ x=getchar(); if(x=='\n')break; s++; h+=a[x-'0']; } printf("%d",min(2*(h+1)+s,2*s+h+1)); }
縮める際の肝は上のコードで配列に保存していた部分をどうするか。
方針としては2通りあって、「いい感じの式をつくる」「bitでやる」
文字の入力の受取も、getchar()-10、~getchar()、read()、などいろいろ考えられるのでいい感じになるものを探す
s,x;main(h){for(;x=getchar()-10;s++)h+=3&397569>>x*2-12;printf("%d",s+h+(s<h?s:h));} s,x;main(h){for(;x=getchar()-10;s++)h+=x/46-~x%2-!(x%8);printf("%d",s+h+(s<h?s:h));} h,x;main(s){for(;x=~getchar();s--)h+=3&1446145>>~x*2;printf("%d",h-s+(-s<h?-s:h));} h,x;main(s){for(;x=~getchar();s--)h-=x/57+x%2+!(x%17);printf("%d",h-s+(-s<h?-s:h));} h,x;main(s){for(;read(0,&x,1);s--)h+=3&1446145>>x*2;printf("%d",h-s+(-s<h?-s:h));} h,x;main(s){for(;read(0,&x,1);s--)h+=x/56-~x%2-!(x%25);printf("%d",h-s+(-s<h?-s:h));} s,x;main(h){for(;read(0,&x,1);s++)h+=x/56-~x%2-!(x%10);printf("%d",h+--s+(s<h?s:h));}
int型に対するbitshiftはmod32で計算される仕様と'0'*2 mod 32が0であることがうまく噛み合って、bitの方が短くなった。
82B