ACM2018年 四川省賽熱身賽 C 題 省賽正式賽 B H E 題 題解
熱身賽 <C>
題意:
給一個數賦初值1,只能對這個數進行*2, +1, -1, 這三種操作,問他能達到所給數的最小步數。
思路:
DP沒得說,但我DP不熟,賽後回味了一下,一直以為是貪心,其實就看當前狀態是怎麼由上一個狀態轉移過來的就好了,要預處理一下,程式碼註釋很詳細。
本人AC程式碼:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 2e6 + 5;
int dp[maxn]; //步數
int n;
int main() {
dp[1] = 0; //1轉移到1步數為0
for(int i = 2; i <= maxn; i++) { //預處理
if(i & 1) { //奇數時
int t1 = dp[(i - 1) / 2] + 2; //由它前一個數乘2加1轉移過來, 所需2步
int t2 = dp[(i + 1) / 2] + 2; //由它前一個數乘2減1轉移過來, 所需2步
int tmp = min(t1, t2);
dp[i] = min(dp[i - 1] + 1, tmp); //由它前一個數加1轉移過來, 所需1步, 然後取上述三者最小值
}
else { //偶數時
int t1 = dp[(i - 2) / 2] + 3; //由它前一個數乘2加1再加1轉移過來, 所需3步
int t2 = dp[(i + 2) / 2] + 3; //由它前一個數乘2減1再減1轉移過來, 所需3步
int tmp = min(t1, t2);
dp[i] = min(dp[i / 2] + 1, tmp); //由它前一個數乘2轉移過來, 所需1步, 然後取上述三者最小值
}
}
while(cin >> n && n) {
cout << dp[n] << endl;
}
}
正賽:
<H>
題意:給兩個數 x, y,求 x + y + Gcd(x, y)
思路:簽到題,水的要命。
本人AC程式碼:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
int gcd(int x, int y) {
if(x % y == 0) return y;
else return gcd(y, x % y);
}
int main() {
int cas;
cin >> cas;
while(cas--) {
int n, m;
cin >> n >> m;
cout << n + m + gcd(n, m) << endl;
}
}
<B>
題意:
給四個串,輸入一個串,看輸入的串是給定四個串裡哪幾個串的不連續子串,區分大小寫。
思路:簽到題,直接暴力就好了,按照所給用string初始化四個串,然後把輸入串的字元按順序列舉即可。寫的有點笨重,沒愛多想,就是個水題,覺得沒必要太優化寫法。當時賽場上那個配置的Vim的strlen( )函式不變色,回來補的時候沒問題了,還是自己的Vim用著舒服。
本人AC程式碼:
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
queue <int> qua;
map <int, int> mp;
int cas;
char s[55];
string s1 = "KanbaraAkihito";
string s2 = "KuriyamaMirai";
string s3 = "NaseHiroomi";
string s4 = "NaseMitsuki";
string ss1 = "Kanbara Akihito";
string ss2 = "Kuriyama Mirai";
string ss3 = "Nase Hiroomi";
string ss4 = "Nase Mitsuki";
int main() {
cin >> cas;
while(cas--) {
int cnt = 0;
scanf("%s", s);
int l = strlen(s);
int c = 0;
bool f1 = 1, f2 = 1, f3 = 1, f4 = 1;
int pos = 0;
for(int i = 0; i < l; i++) {
for(int j = pos; j < 15; j++) {
if(s1[j] == s[i]) {
c++;
pos = j + 1;
break;
}
}
}
if(c >= l) cnt++;
else f1 = 0;
c = 0;
pos = 0;
for(int i = 0; i < l; i++) {
for(int j = pos; j < 14; j++) {
if(s2[j] == s[i]) {
c++;
pos = j + 1;
break;
}
}
}
if(c >= l) cnt++;
else f2 = 0;
c = 0;
pos = 0;
for(int i = 0; i < l; i++) {
for(int j = pos; j < 12; j++) {
if(s3[j] == s[i]) {
c++;
pos = j + 1;
break;
}
}
}
if(c >= l) cnt++;
else f3 = 0;
c = 0;
pos = 0;
for(int i = 0; i < l; i++) {
for(int j = pos; j < 12; j++) {
if(s4[j] == s[i]) {
c++;
pos = j + 1;
break;
}
}
}
if(c >= l) cnt++;
else f4 = 0;
cout << cnt << endl;
if(f1) cout << ss1 << endl;
if(f2) cout << ss2 << endl;
if(f3) cout << ss3 << endl;
if(f4) cout << ss4 << endl;
}
}
<E>
題意:
日期的表示方法有兩種,月/日/年 and 年/月/日,按照格式輸入a / b / c,看符合兩種表示方式的哪種,如果都符合,就輸出這不同兩天之間相差多少天;如果只有一種合法或者兩種表示方法是同一天,比如 01/02/03 和 02/02/02 ,則按月日年形式輸出唯一合法的日期,至少有一種表示方式合法。
思路:
最噁心的簽到,給我噁心完了簡直,回來補題換了種很系統的寫法,先寫一個chk函式判斷日期合法與否,如下:
bool chk(int y, int m, int d) {
bool flg = 1;
if(m > 12 || m == 0) flg = 0;
if(m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 || m == 12) {
if(d == 0 || d > 31) flg = 0;
}
else if(m == 4 || m == 6 || m == 9 || m == 11) {
if(d == 0 || d > 30) flg = 0;
}
else if(m == 2) {
if( (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0) ) {
if(d == 0 || d > 29) flg = 0;
}
else {
if(d == 0 || d > 28) flg = 0;
}
}
return flg;
}
再將輸入的兩種表示形式都寫出來,看有幾個合法,如果兩個合法,那就分別算他倆與2000/1/1之間的天數,再求差取絕對值即可,如果只有一種滿足,那就按題意輸出即可,沒什麼難度,但是非常考驗C語言功底,雖然我不是大佬可能沒資格說這種話,但是,還是建議初學者認真做一下這題,如果這種噁心題一直扔著不做,以後碰到噁心題就永遠做不出來,畢竟身為ACM,AC即一切,如果這題WA到比賽結束,說什麼都白扯,話不多說,放下我程式碼。
本人AC程式碼:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
map <int, int> mp;
queue <int> qua;
stack <char> stk;
vector <int> vec;
set <int> st;
int cas;
char s[12];
int a, b, c;
string M[13];
bool chk(int y, int m, int d) {
bool flg = 1;
if(m > 12 || m == 0) flg = 0;
if(m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 || m == 12) {
if(d == 0 || d > 31) flg = 0;
}
else if(m == 4 || m == 6 || m == 9 || m == 11) {
if(d == 0 || d > 30) flg = 0;
}
else if(m == 2) {
if( (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0) ) {
if(d == 0 || d > 29) flg = 0;
}
else {
if(d == 0 || d > 28) flg = 0;
}
}
return flg;
}
int main() {
cin >> cas;
while(cas--) {
int D[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
M[1] = "January", M[2] = "February", M[3] = "March", M[4] = "April", M[5] = "May", M[6] = "June";
M[7] = "July", M[8] = "August", M[9] = "September", M[10] = "October", M[11] = "November", M[12] = "December";
memset(s, 0, sizeof(s)); //這句必須加,雖然不知道為啥需要清空,但是不清空就會WA
scanf("%s", s);
a = s[1] - '0' + 10 * (s[0] - '0');
b = s[4] - '0' + 10 * (s[3] - '0');
c = s[7] - '0' + 10 * (s[6] - '0');
int ya = 2000 + a, ma = b, da = c;
int yb = 2000 + c, mb = a, db = b;
/* 測一下輸出
cout << ya << "/" << ma << "/" << da << endl; //年月日
if(chk(ya, ma, da)) cout << "Yes" << endl;
else cout << "No" << endl;
cout << yb << "/" << mb << "/" << db << endl; //月日年
if(chk(yb, mb, db)) cout << "Yes" << endl;
else cout << "No" << endl;
*/
if(chk(ya, ma, da) + chk(yb, mb, db) == 2) {
if(ya == yb && ma == mb && da == db) { //兩種都合法看是不是同一天
cout << M[ma];
printf(" %d, %d\n", da, ya);
}
else {
int ans = 0, res = 0;
for(int i = 2000; i <= ya - 1; i++) {
if( (i % 4 == 0 && i % 100 != 0) || (i % 400 == 0) ) ans += 366;
else ans += 365;
}
if( (ya % 4 == 0 && ya % 100 != 0) || (ya % 400 == 0) ) D[2]++;
for(int i = 1; i <= ma - 1; i++) ans += D[i];
ans += da;
D[2] = 28;
for(int i = 2000; i <= yb - 1; i++) {
if( (i % 4 == 0 && i % 100 != 0) || (i % 400 == 0) ) res += 366;
else res += 365;
}
if( (yb % 4 == 0 && yb % 100 != 0) || (yb % 400 == 0) ) D[2]++;
for(int i = 1; i <= mb - 1; i++) res += D[i];
res += db;
cout << abs(ans - res) << endl;
}
}
else {
if(chk(ya, ma, da)) {
cout << M[ma];
printf(" %d, %d\n", da, ya);
}
else if(chk(yb, mb, db)) {
cout << M[mb];
printf(" %d, %d\n", db, yb);
}
}
}
}