epoch@まつやまの予選通過!
通らないと思ってたepochの予選が去年についで今年も無事通過しました。予想外なのでかなりうれしい。なぜ通らないと思ってたかはあとから書きます。
相方は@wand125(id:w125)で、チーム名はもふもふあるぱか。去年のチーム名はふわふわどーなつでした。由来はtwitterのアイコンから。
予選問題のコードは6~7割くらい僕が書きました。詳細は以下。
問題1
sortしてごにょごにょするだけ。
最初自分が書いた時は変なことをしててかなり遅かったので、相方のコードをちょっとだけ変えて送りました。この問題に限らず、入力はfgetsのほうがscanfより断然速い。
#include <cstdio> #include <cstdlib> #include <algorithm> using namespace std; #define SIZE 500000 #define INF 1000000 int main(void){ int N; int data[SIZE+1]; int once[SIZE+1]; int idx = 0; int max_of_twice = INF; char buf[256]; fgets(buf, 256, stdin); N = atoi(buf); for(int i = 0; i < N; i++){ fgets(buf, 256, stdin); data[i] = atoi(buf); } sort(data, data + N); for(int i = 0; i < N; i++){ if(i + 1 < N && data[i] == data[i+1]){ max_of_twice = data[i]; while(i + 1 < N && data[i] == data[i+1]) i++; }else{ once[idx++] = data[i]; } } printf("%d\n",once[idx - min(max_of_twice,idx)]); return 0; }
問題2
コード汚いです。(今ちょっとだけ直した。)下から順番に見てstackに入れていく感じ。
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <stack> using namespace std; char str[100001][256]; //1-insert 2-delete 3-change 4-same 0-none int judge(const char* str1, const char* str2){ int s1 = strlen(str1); int s2 = strlen(str2); int diff = abs(s1 - s2); int misscount = 0; if(diff > 1){ return 0; }else if(diff == 1){ bool swaped = false; if(s1 < s2){ swap(str1,str2); swaped = true; } while(*str1 && *str2){ if(*str1++ == *str2){ str2++; }else{ misscount++; } if(misscount > 1) break; } if(!*str2){ return (swaped)?1:2; } }else if(diff == 0){ while(*str1){ if(*str1++ != *str2++){ misscount++; } if(misscount > 1) break; } return (misscount)?3:4; } return 0; } int main(void){ int N; int ope; long long ans = 0; stack<int> operation; char buf[1024]; fgets(buf, 1024, stdin); N = atoi(buf); for(int i = 0; i < N; i++){ fgets(str[i], 1024, stdin); str[i][strlen(str[i]) - 1] = '\0'; } for(int i=N-1; i-1>=0; i--){ if( !(ope = judge(str[i-1], str[i])) ){ break; } operation.push(ope); } while(!operation.empty()){ ope = operation.top(); operation.pop(); switch(ope){ case 1: ans += 1; break; case 2: ans += -1; break; case 3: ans += 2; break; case 4: ans *= 2; break; } } printf("%lld\n",ans); return 0; }
問題3
「最上位桁に 0 が現れてもよい」。この条件が入ってるせいで難しかった。これがなければ桁数から簡単に探索できるのだけど、この問題だとうまく工夫しないといけない。で書いたコードがこれなのだけど、これだと100011111121のようなケースで誤判定する。これに気づいたのが予選が終わった日の夜ぐらいで、相方に教えてもらって絶望してた記憶がある。ちなみに提出したコードはこれじゃなくて、相方が書き換えて速くしてくれました。
#include <cstdio> #include <cstdlib> #include <cstring> void printexp(char str[], int i, int j, int len){ for(int l = 0; l < len; l++){ if(l == i) putchar('+'); if(l == j) putchar('='); putchar(str[l]); } putchar('\n'); } bool equal(char str[], int i, int j, int len){ //[0,i)+[i,j)=[j,len) int idx1, idx2, idx3, dig, up; //dig:各桁の値 up:繰り上げの値 if(!(0 < i && i < j && j < len)){ return false; } for(idx1 = i-1, idx2 = j-1, idx3 = len-1, up = 0, dig = 0; idx1 >= 0 || idx2 >= i || idx3 >= j || up != 0; idx1--,idx2--,idx3--,dig = 0){ dig += up; up = 0; //繰り上げ処理 if(idx1 >= 0) dig += (str[idx1]-'0'); if(idx2 >= i) dig += (str[idx2]-'0'); if(dig >= 10){ up = dig/10; dig %= 10; } if(idx3 >= j) dig -= (str[idx3]-'0'); if(dig != 0){ return false; } } return true; } bool judge(char str[]){ int len = strlen(str); int rcnt = 0; //右辺の桁数 int initialZero = 0; //頭のゼロの数 for(int i = 0; i < len; i++){ if(str[i] == '0'){ initialZero++; }else{ break; } } if(initialZero == len) return true; //すべての桁が0 for(int j = len - 1; j - 1 > 0; j--){ if(str[j] != '0'){ rcnt = (len - j); } if( equal(str, initialZero + (rcnt - 1), j, len) || equal(str, initialZero + rcnt , j, len) || equal(str, j - (rcnt - 1), j, len) || equal(str, j - rcnt, j, len) ){ return true; } } return false; } int main(void){ int N; int ans = 0; char str[1024]; fgets(str, 1024, stdin); N = atoi(str); while(N--){ fgets(str, 1024, stdin); str[strlen(str) - 1] = '\0'; if(judge(str)) ans++; } printf("%d\n",ans); return 0; }