JXNU團體程序設計天梯賽訓練賽(一)題解

1001 數翻轉
思路:這題其實並不難,就是要把後面的0全部去掉,然後計算還剩下來多少個字符,直接模擬就好了,唯一可能的坑點就是:0要特殊判斷,因爲0也是1位數字,所以最後的一個0是不能去掉的,只需要對中國特判一下就好了。

#include <iostream>
#include <string>
using namespace std;
int main() {
    cin.sync_with_stdio(false);
    int n, i;
    string str;
    cin >> n;
    for (int j = 0; j < n; j++) {
        cin >> str;
        for (i = str.size() - 1; i >= 0; i--) {
            if (str[i] != '0') {
                break;
            }
        }
        if (i == -1) {
            cout << 1 << endl;
        }
        else {
            cout << i + 1 << endl;
        }
    }
    return 0;
}

1002 探險
思路:就是一個簡單的DFS,從起點開始遞歸,我們只需要知道在每一次遞歸的時候判斷這個點能不能走,並且判斷該點有沒有走過,有沒有超過地圖的範圍。如果都是可以的,那就說明這個點可以走,然後標記這個點走過了(因爲如果以後還走到這個點就沒有必要走了,因爲迭代回來的時候就會走下面這個路了),之後開始接着進行遞歸,當回來的時候把這個標記取消掉就好了。最後到了終點做一個標記就好了。最後判斷標記就能判斷能不能從起點到終點。

#include <iostream>
#include <string>
#define N 110
using namespace std;
char mapp[N][N];
int sx, sy, ex, ey;
int T, n, m;
int dir[4][2] = { { 1,0 },{ -1,0 },{ 0,1 },{ 0,-1 } };
bool dfs(int x, int y) {
    for (int i = 0; i < 4; i++) {
        int xx = x + dir[i][0];
        int yy = y + dir[i][1];
        if (xx == ex&&ey == yy) {
            return true;
        }
        if (xx > 0 && yy > 0 && xx <= n&&yy <= m&&mapp[xx][yy] == '-') {
            mapp[xx][yy] = '*';
            if (dfs(xx, yy)) {
                return true;
            }
            mapp[xx][yy] = '-';
        }
    }
    return false;
}
int main() {
    cin.sync_with_stdio(false);
    cin >> T;
    while (T--) {
        cin >> n >> m;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                cin >> mapp[i][j];
                if (mapp[i][j] == 'S') {
                    sx = i;
                    sy = j;
                }
                else if (mapp[i][j] == 'D') {
                    ex = i;
                    ey = j;
                }
            }
        }
        if (dfs(sx, sy))
            cout << "yes" << endl;
        else {
            cout << "no" << endl;
        }
    }
    return 0;
}

1003 打印矩陣
思路:直接按照要求通過循環進行打印就好了。

#include <iostream>
using namespace std;
int main() {
    cin.sync_with_stdio(false);
    int T, n, m;
    char c;
    cin >> T;
    while (T--) {
        cin >> n >> c;
        m = (n + 1) / 2;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                cout << c;
            }
            cout << endl;
        }
    }
    return 0;
}

1004 沙漏
思路:這裏面就是遞推和模擬組合的題目了,因爲我們要儘可能的用完字符,所以我們只需要打印出來所有層數的最佳方案需要多少字符,我們就可以發現其實當1層的時候字符數是1,當3層的時候,當上半部分就是加上了4個(因爲加上了帶有空的一層,以及最高的一層加上了2個字符),下半部分就是加上了層數的字符(因爲沒有空心的),現在我們就能得到所有層數最好的字符數量了,我們只需要根據得到的字符數,判斷出最大的比這個字符數量小或者等於的字符數的層數,最後通過得到的層數打印就好了(打印的規律看代碼,或者畫圖就能知道了)。

#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <iomanip>
#define N 1010
using namespace std;
vector<int> num;
int main() {
    cin.sync_with_stdio(false);
    char c;
    int n, ans;
    ans = 7;
    num.push_back(1);
    num.push_back(7);
    for (int i = 5; ; i+=2) {
        ans = ans + 4 + i;
        if (ans > 10000) {
            break;
        }
        num.push_back(ans);
    }
    while (cin >> n >> c) {
        for (int i = 0; i < num.size(); i++) {
            if (num[i] <= n) {
                ans = 2 * i + 1;
            }
            else {
                break;
            }
        }
        int cnt = ans / 2 - 1;
        for (int i = 0; i < ans; i++) {
            cout << c;
        }
        cout << endl;
        for (int i = 1; i <= cnt; i++) {
            for (int j = 0; j < i; j++) {
                cout << " ";
            }
            cout << c;
            for (int j = i + 1; j < ans - i - 1; j++) {
                cout << " ";
            }
            cout << c << endl;
        }
        for (int i = 0; i <= cnt; i++) {
            cout << " ";
        }
        cout << c << endl;
        for (int i = 0; i <= cnt; i++) {
            for (int j = 0; j < cnt - i; j++) {
                cout << " ";
            }
            for (int j = cnt - i + 1; j <= ans - cnt + i; j++) {
                cout << c;
            }
            cout << endl;
        }
    }
    return 0;
}

1005 shopping
思路:簡單的三維揹包,三維分別是花費的人民幣,花費的積分,花費的免費次數,然後和普通的揹包一樣就可以了,只不過這次不是隻需要考慮一個條件,而是三個條件,然後因爲只與上一層有關係,所以只需要記錄上一層的情況就好了。

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<ctime>
#define ll long long int
#define eps 0.0000001
#define fo1(s,e) for(ll i=s;i<=e;i++)
#define fo2(s,e) for(ll j=s;j<=e;j++)
#define mem(a,n) memset(a,n,sizeof(a))
#define mod 1000000007
#define maxn 100005
#define inf 0x3f3f
#define pi acos(-1.0)
const ll INF=1e18;
using namespace std;
int dp[2][105][105][10];
int c1[105],c2[105],val[105];
int main() {
    int n,v1,v2,k;
    while(scanf("%d%d%d%d",&n,&v1,&v2,&k)!=EOF){
        int i;
        for(i=1;i<=n;i++)
            scanf("%d%d%d",&c1[i],&c2[i],&val[i]);
        memset(dp,0,sizeof(dp));
        int now=0;
        for(i=1;i<=n;i++){   
            now=1-now;
            for(int j=0;j<=v1;j++){
                for(int l1=0;l1<=v2;l1++){
                    for(int l2=0;l2<=k;l2++){    
                        dp[now][j][l1][l2]=dp[1-now][j][l1][l2];
                        if(j>=c1[i])
            dp[now][j][l1][l2]=max(dp[now][j][l1][l2],dp[1-now][j-c1[i]][l1][l2]+val[i]);
                        if(l1>=c2[i])
            dp[now][j][l1][l2]=max(dp[now][j][l1][l2],dp[1-now][j][l1-c2[i]][l2]+val[i]);
                        if(l2>=1)
            dp[now][j][l1][l2]=max(dp[now][j][l1][l2],dp[1-now][j][l1][l2-1]+val[i]);
                    }
                }
            }
        }
        printf("%d\n",dp[now][v1][v2][k]);
    }
    return 0;
}

1006 數字整除問題
思路:我們可以單獨求出能被3整除,被5整除,被7整除的數的個數,但是可能有的數會被多個數整除,這樣就會重複計算了,所以就要用到容斥定理:A∪B∪C=A+B+C-A∩B-A∩C-B∩C+A∩B∩C。這樣我們就可以算出來有多少個符合要求的數字了。

#include<iostream>
using namespace std;
#define LL long long
int main(){
    ios::sync_with_stdio(false);
    LL n;
    int T;
    cin>>T;
    while(T--){
        cin>>n;
        LL ans=n/3+n/5+n/7-n/3/5-n/3/7-n/5/7+n/3/5/7;
        cout<<ans<<endl;
    }
    return 0;
}

1007 甜甜圈
思路:其實我們可以發現一個規律,0-9這十個數只有8是兩個圈的,所以先全部輸出8,這樣就能在一位消耗2個圈了,然後我們就會發現4是最小的數是一個圈,如果是奇數的時候在最前面輸出一個4就好了,因爲4比8小。但是我們要進行特判,因爲當只要1個圈的時候最小的應該是0。

#include <iostream>
#include <string>
#define N 110
using namespace std;
int main() {
    cin.sync_with_stdio(false);
    int T, n;
    cin >> T;
    while (T--) {
        cin >> n;
        if (n == 1) {
            cout << 0 << endl;
            continue;
        }
        if (n % 2) {
            cout << 4;

        }
        for (int i = 0; i < n / 2; i++) {
            cout << 8;
        }
        cout << endl;
    }
    return 0;
}

1008 逢7
思路:因爲數據量就只有10^5,所以直接打表,先把1~10^5的數中每個1~n的逢7的數字的數量全部打出來(類似前綴和中的思想,但是後面都是從1開始,所以只需要這個數組的值,不需要相減),然後直接輸出就好了。

#include <iostream>
#define N 100000
#define M 100010
using namespace std;
int num[N];
bool ok(int ans) {//判斷是不是數字中含有7
    while (ans) {
        if (ans % 10 == 7) {
            return true;
        }
        ans /= 10;
    }
    return false;
}
int main() {
    cin.sync_with_stdio(false);
    num[0] = 0;
    for (int i = 1; i <= N; i++) {
        if (i % 7 == 0 || ok(i)) {
            num[i] = num[i - 1] + 1;
        }
        else {
            num[i] = num[i - 1];
        }
    }
    int n, m;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> m;
        cout << num[m] << endl;
    }
    return 0;
}

1009 除法
思路:對除數0進行特判,然後用浮點數進行計算,因爲是四捨五入,所以把結果加上0.5再強制類型轉換爲int輸出就好了。

#include <iostream>
#include <string>
#define N 110
using namespace std;
int main() {
    cin.sync_with_stdio(false);
    int T, n, m;
    cin >> T;
    while (T--) {
        cin >> n >> m;
        if (m == 0) {
            cout << "Invalid" << endl;
        }
        else {
            cout << (int)((n *1.0)/ m+0.5) << endl;
        }
    }
    return 0;
}

1010 惇哥的數組
思路:因爲是不斷取有個區間中的中值進行輸出,所以我們直接通過遞歸來模擬就好了,每一層的遞歸傳入的值就是這個區間的左右端點值,然後我們直接輸出這個區間的中值就好了,然後再以這個中值爲分割點,把區間分割成左右區間以及中值,然後分別對左右區間進行遞歸,遞歸的結尾就是不能構成數組了(右端點比左端點的下標值大),這時候我們直接返回就好了(優化:有個特殊情況就是這個區間就一個數的時候直接輸出就好了,這樣就不用進入下一層遞歸了)。

#include <iostream>
#include <string>
#define N 1010
using namespace std;
int num[N];
int T, n;
void print(int a, int b) {
    if (b < a) {
        return;
    }
    if (a == b) {
        cout << num[a] << " ";
        return;
    }
    int mid = (a + b) / 2;
    cout << num[mid] << " ";
    print(a, mid - 1);
    print(mid + 1, b);
}
int main() {
    cin.sync_with_stdio(false);
    cin >> T;
    while (T--) {
        cin >> n;
        for (int i = 1; i <= n; i++) {
            cin >> num[i];
        }
        print(1,n);
        cout << endl;
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章