2020第十一屆軟件類省內模擬賽(非官方)

1. 字節計算

  思路 :直接計算器計算即可。

//在計算機存儲中,12.5MB是多少字節?
#include<bits/stdc++.h>
using namespace std;

int main() {
	cout << 13107200 << endl;
	return 0;
} 

2. 無向連通圖

  思路 :直接計算即可。

//一個包含有2019個結點的無向連通圖,最少包含多少條邊?
#include<bits/stdc++.h>
using namespace std;

int main() {
	cout << 2018 << endl;
	return 0;
} 

3. 藍橋單詞(組合)

  思路 :高中數學,首先對字母進行全排列 A77A^{7}_{7},但是由於有兩個重複字母 A77/A22A^{7}_{7} / A^{2}_{2}

#include<bits/stdc++.h>
using namespace std;

int main() {
	cout << 2520 << endl;
	return 0;
} 

4. 合法括號序列(dfs)

  思路 :直接全排列判斷有多少符合題意。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

bool check (string str) {
    int n = str.length();
    stack<char> s;
    for (int i = 0; i < n; ++ i) {
        if (str[i] == '(') s.push(str[i]);
        else {
            if (s.size()) {
                if (s.top() == '(') s.pop();
            } else s.push(str[i]);
        }
    }
    return s.size();
}

int main () {
    string str = "(((())))";
    int ans = 0;
    do {
        //cout << str << endl;
        if (!check(str)) ++ ans;
    } while (next_permutation(str.begin(), str.end()));
    cout << ans << endl;
    return 0;
}

5. 單詞加密(模擬)

  思路 :直接按照題意枚舉即可。

//解密
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 1e3 + 10;
char str[maxn];

int main() {
	scanf("%s", str);
	int n = strlen(str);
	for (int i = 0; i < n; ++ i) {
		if (str[i] == 'x') str[i] = 'a';
		else if (str[i] == 'y') str[i] = 'b';
		else if (str[i] == 'z') str[i] = 'c';
		else str[i] = str[i] + 3;
	} 
	//puts(str);
	for (int i = 0; i < n; ++ i) printf("%c", str[i]);
	printf("\n");
	return 0;
}

6. 反倍數(枚舉)

  思路 :直接遍歷給出的數判斷計數即可。

//反倍數
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 1e6 + 10;

int main() {
	int n; scanf("%d", &n);
	int a, b, c; scanf("%d%d%d", &a, &b, &c);
	int cnt = 0;
	for (int i = 1; i <= n; ++ i) {
		if (i % a != 0 && i % b != 0 && i % c != 0) {
			//cout << i << " ";
			cnt ++;
		}
	}
	printf("%d\n", cnt);
	return 0;
}

7. 螺旋矩陣(枚舉 + 標記)

  思路 :首先對矩陣進行一個標記,然後從第一個格子開始進行填數,填過數的格子標記爲 falsefalse,直到所有的格子都標記完畢即可。

//矩陣
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 1e3 + 10;
int mat[maxn][maxn];
bool vis[maxn][maxn];

int main() {
	int n, m; scanf("%d%d", &n, &m);
	int r, c; scanf("%d%d", &r, &c);
	for (int i = 1; i <= n; ++ i) {
		for (int j = 1; j <= m; ++ j) vis[i][j] = false;
	}
	int cnt = 1, x = 1, y = 0;
	while (cnt <= n * m) {
		while (!vis[x][y + 1]) {
			mat[x][++ y] = cnt ++;
			vis[x][y] = true;
			if (y == m) break;
		}
		while (!vis[x + 1][y]) {
			mat[++ x][y] = cnt ++;
			vis[x][y] = true;
			if (x == n) break;
		}
		while (!vis[x][y - 1]) {
			mat[x][-- y] = cnt ++;
			vis[x][y] = true;
			if (y == 1) break;
		}
		while (!vis[x - 1][y]) {
			mat[-- x][y] = cnt ++;
			vis[x][y] = true;
			if (x == 1) break;
		}
	}
	/*for (int i = 1; i <= n; ++ i) {
		for(int j = 1; j <= m; ++ j) cout << mat[i][j] << " ";
		cout << endl;
	}*/
	printf("%d\n", mat[r][c]);
	return 0;
}

8. 擺動序列(dp)

  • 50% 數據
      思路 :直接按照題意 dfsdfs 即可。
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int mod = 10000;
const int maxn = 1e3 + 10;
int ans = 0, m, n;

void dfs(int now, int cnt) {
	if (cnt == m) {
		ans = (ans + 1) % mod;
		return ;
	} 
	for (int i = 1; i <= n; ++ i) {
		if (!cnt) dfs(i, cnt + 1);
		else {
			if (cnt & 1 && i < now) dfs(i, cnt + 1);
			if (!(cnt & 1) && i > now) dfs(i, cnt + 1);
		}
	}
}

int main() {
	scanf("%d%d", &m, &n);
	dfs(-1, 0);
	printf("%d\n", ans);
	return 0;
}
  • 80% 數據
      思路 :奇數項都比前一項大,偶數項都比前一項小,設 dp[i][j]dp[i][j] 表示第 ii 個數字,選擇 jj 時一共有多少種。噹噹前的數是奇數項的時候,那麼前面一項小於 jj 的和可以推出當前項的種數,如果當前數是偶數項的時候,那麼前面一項大於 jj 的狀態的和可以推出當前項,也就是(記得最終結果取模)
    dp[i][j]+=dp[i1][k],k[1,j),i%2==1dp[i][j] += dp[i - 1][k], k ∈[1, j), i\%2==1
    dp[i][j]+=dp[i1][k],k[j+1,n],i%2==0dp[i][j] += dp[i - 1][k], k ∈[j + 1, n], i\%2==0
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 1e3 + 10;
const int mod = 10000;
int dp[maxn][maxn];//第i個數字選擇j的種數

//奇數項都比前一項大,偶數項都比前一項小,種數
int main () {
    int m, n;
    scanf("%d%d", &m, &n);
    for (int i = 0; i <= m; ++ i) {
        for (int j = 0; j <= n; ++ j) {
            dp[i][j] = 0;
        }
    }
    for(int i = 1; i <= n; ++ i) dp[1][i] = 1;
    for (int i = 2; i <= m; ++ i) {
        if (i & 1) {
            for (int j = 1; j <= n; ++ j) {
                for (int k = 1; k < j; ++ k) {
                    dp[i][j] += dp[i - 1][k];
                    dp[i][j] %= mod;
                }
            }
        } else {
            for (int j = 1; j <= n; ++ j) {
                for (int k = j + 1; k <= n; ++ k) {
                    dp[i][j] += dp[i - 1][k];
                    dp[i][j] %= mod;
                }
            }
        }
    }
    /*for (int i = 1; i <= m; ++ i) {
        for (int j = 1; j <= n; ++ j) cout << dp[i][j] << " ";
        cout << endl;
    }*/
    int ans = 0;
    for (int i = 1; i <= n; ++ i) ans = (ans + dp[m][i]) % mod;
    printf("%d\n", ans);
    return 0;
}
  • 100% 數據
      思路 :可以對上面的程序進行數據的輸出,當前行 ii 的值的總和表示長度爲 ii 的擺動序列一共有多少種。如果上面的程序做一個前綴和的操作就可以對上面程序作出一個改進,我們對上面的程序進行改進,當 i==1i == 1 的時候,dp[i][j]dp[i][j] 表示第 ii 個數大於等於 jj 的時候的種數,這時如果當前項是偶數項的時候,它的前面一項是奇數項,我們需要使用前面一項大於等於 jj 的結果來推算出當前的結果,在加上使用前綴和優化,就有 dp[i][j]=dp[i1][j+1]+dp[i][j1]dp[i][j] = dp[i - 1][j + 1] + dp[i][j - 1],當前項是奇數項的時候我們可以使用前面一項,也就是偶數項的小於等於 j1j - 1 的這種狀態得到,所以有 dp[i][j] = (dp[i - 1][j - 1] + dp[i][j + 1])(從 80% 的程序中輸出結果矩陣,可以發現一些規律,奇數行都是從大到小,偶數行都是從小到大。)
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 1e3 + 10;
const int mod = 10000;
int dp[maxn][maxn];

//奇數項都比前一項大,偶數項都比前一項小,種數
int main () {
    int m, n;
    scanf("%d%d", &m, &n);
    for (int i = 0; i <= m; ++ i) {
        for (int j = 0; j <= n; ++ j) {
            dp[i][j] = 0;
        }
    }
    for(int i = 1; i <= n; ++ i) dp[1][i] = n - i + 1; //大於等於i的數量
    for (int i = 2; i <= m; ++ i) {
        if (i & 1) {
            /*for (int j = 1; j <= n; ++ j) {
                for (int k = 1; k < j; ++ k) {
                    dp[i][j] += dp[i - 1][k];
                    dp[i][j] %= mod;
                }
            }*/
            //前面一行是偶數行<=j-1
            for (int j = n; j >= 1; -- j) dp[i][j] = (dp[i - 1][j - 1] + dp[i][j + 1]) % mod;
        } else {
            /*for (int j = 1; j <= n; ++ j) {
                for (int k = j + 1; k <= n; ++ k) {
                    dp[i][j] += dp[i - 1][k];
                    dp[i][j] %= mod;
                }
            }*/
            //前面一行是奇數行>=j+1
            for (int j = 1; j <= n; ++ j) dp[i][j] = (dp[i - 1][j + 1] + dp[i][j - 1]) % mod;
        }
    }
    int ans = (m & 1) ? dp[m][1] : dp[m][n];
    //優化代碼中這裏變成加上一個前綴和
    //for (int i = 1; i <= n; ++ i) ans = (ans + dp[m][i]) % mod;
    printf("%d\n", ans);
    return 0;
}

9. 郊外植樹(dfs + 剪枝)

  思路 :由於數據範圍比較小,我們可以直接 dfsdfs,此題的優化點在於在判斷當前選擇的圓是否和之前已經選擇好的圓衝突。設置一個估價函數來進行剪枝,對圓按照半徑從大到小排序之後,我們記錄下從所有圓的面積的後綴和,在我們搜索的時候如果當前的面積加上後綴的面積還沒有已經得到的面積大那麼就進行返回,同時我們使用了一個二進制的數來記錄了每個圓的選擇狀態,當我們選擇當前的圓的時候首先判斷是否和已經選擇過的圓衝突,如果衝突則不選擇當前圓,如果不衝突則選擇當前圓。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 40;
bool vis[maxn][maxn];
int suf[maxn];

struct Node {
    int x, y, r;
    bool operator < (const Node & xxx) const {
        return r > xxx.r;
    }
}node[maxn];

int n, ans = 0;
map<int, int> m;

int dis2(int i, int j) {
    return (node[i].x - node[j].x) * (node[i].x - node[j].x) + (node[i].y - node[j].y) * (node[i].y - node[j].y);
}

void dfs(int now, int sum, int status) {
    if (now > n) {
        ans = max(ans, sum);
        return ;
    }
    if (ans > sum + suf[now]) return ;
    bool flag = true;
    int j = 0;
    for (int i = status; i; i -= j) {
        j = i & (-i);
        if (vis[now][m[j]]) flag = false;
        if (!flag) break;
    }
    if (flag) dfs(now + 1, sum + node[now].r * node[now].r, status | (1 << now));
    dfs(now + 1, sum, status);
}

int main () {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++ i) for (int j = 1; j <= n; ++ j) vis[i][j] = false;
    /*for (int i = 1; i <= n; ++ i) {
        for (int j = 1; j <= n; ++ j) cout << vis[i][j] << " ";
        cout << endl;
    }*/
    for (int i = 1; i <= n; ++ i) {
        scanf("%d %d %d", &node[i].x, &node[i].y, &node[i].r);
        m[1 << i] = i;
    }
    sort(node + 1, node + n + 1);
    for (int i = 1; i <= n; ++ i) {
        for (int j = 1; j <= n; ++ j) {
            if (dis2(i, j) < (node[i].r + node[j].r) * (node[i].r + node[j].r)) vis[i][j] = true;
        }
    }
    /*for (int i = 1; i <= n; ++ i) {
        for (int j = 1; j <= n; ++ j) cout << vis[i][j] << " ";
        cout << endl;
    }*/
    for (int i = n; i >= 1; -- i) suf[i] = suf[i + 1] + node[i].r * node[i].r;
    dfs(1, 0, 0);
    printf("%d\n", ans);
    return 0;
}

10. 村莊建設(mst)

  思路 :MST 裸題,注意數據類型即可。

//植樹
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 1e3 + 10;
int f[maxn];

struct Node {
	int x, y, h, num;
}node[maxn];

struct Edge {
	int u, v;
	double cost;
	bool operator < (const Edge & xxx) const {
		return cost < xxx.cost;
	}
}edge[maxn * maxn];

double dis(Node a, Node b) {
	return sqrt(1ll * (a.x - b.x) * (a.x - b.x) + 1ll * (a.y - b.y) * (a.y - b.y)) + 1ll * (a.h - b.h) * (a.h - b.h) * 1.0;
}

int Find(int v) {
	if (v == f[v]) return v;
	else return f[v] = Find(f[v]);	
}

bool Merge(int u, int v) {
	int t1 = Find(u), t2 = Find(v);
	if (t1 != t2) {
		f[t1] = t2;
		return true;
	}
	return false;
}

int main () {
	int n; scanf("%d", &n);
	for (int i = 1; i <= n; ++ i) f[i] = i;
	for (int i = 1; i <= n; ++ i) {
		scanf("%d%d%d", &node[i].x, &node[i].y, &node[i].h);
		node[i].num = i;
	}
	int cnt = 0;
	for (int i = 1; i <= n; ++ i) {
		for (int j = i + 1; j <= n; ++ j) {
			edge[cnt].u = node[i].num;
			edge[cnt].v = node[j].num;
			edge[cnt ++].cost = dis(node[i], node[j]);
		}
	}
	sort(edge, edge + cnt);
	double ans = 0;
	int cntEdge = 0;
	for (int i = 0; i < cnt; ++ i) {
		if (Merge(edge[i].u, edge[i].v)) {
			++ cntEdge; ans += edge[i].cost;
			if (cntEdge == n - 1) break;
		}
	}
	printf("%.2f\n", ans);
	return 0;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章