官方题解:蓝桥杯近 3 年省赛真题讲解(C&C++ 大学 A 组)_数据结构 - 蓝桥云课
历届真题:蓝桥杯大赛历届真题 - C&C++ 大学 A 组 - 蓝桥云课
#include
using namespace std;
int cnt[15];
int main()
{
for(int i = 0 ; i <= 9 ; i ++ ) cnt[i] = 2021;
for(int i = 1 ; ; i ++ )
{
int k = i;
while(k != 0)
{
if( cnt[k % 10] != 0 ) cnt[k % 10] --;
else
{
cout << i - 1;
return 0;
}
k /= 10;
}
}
}
注意map是数组类型,按key值查询value值,因此是二维的,而set是集合,没有value值,因此是一维的。
set<pair<double, double> > ss;
map<pair<double, double>, int> mp; //必须要有一个int或者其他类型的value值
这道题的本质是对所有的直线进行一个去重处理,因此map和set都可以使用,set更简单点。
需要着重注意的是细节类问题
//set
#include
using namespace std;
set<pair<double, double> > ss;
pair<int, int> point[500];
int idx;
int main()
{
for(int i = 0 ; i < 20 ; i ++ )
for(int j = 0 ; j < 21 ; j ++ )
point[idx ++] = {i, j};
for(int i = 0 ; i < idx ; i ++ )
for(int j = i + 1 ; j < idx ; j ++ )
{
int x1 = point[i].first, y1 = point[i].second;
int x2 = point[j].first, y2 = point[j].second;
if(x2 == x1) continue;
double k = (double)(y2 - y1)/(x2 - x1);
double b = (double)(x2*y1 - x1*y2)/(x2 - x1);
ss.insert({k, b});
}
cout << ss.size() + 20;
return 0;
}
// map
#include
using namespace std;
map<pair<double, double>, int> mp;
pair<int, int> point[500];
int idx;
int ans = 20;
int main()
{
for(int i = 0 ; i < 20 ; i ++ )
for(int j = 0 ; j < 21 ; j ++ )
point[idx ++] = {i, j};
for(int i = 0 ; i < idx ; i ++ )
for(int j = i + 1 ; j < idx ; j ++ )
{
int x1 = point[i].first, y1 = point[i].second;
int x2 = point[j].first, y2 = point[j].second;
if(x2 == x1) continue;
double k = (double)(y2 - y1)/(x2 - x1);
double b = (double)(x2*y1 - x1*y2)/(x2 - x1);
if(mp[{k, b}] == 0)
{
mp[{k, b}] = 1;
ans ++;
}
}
cout << ans;
return 0;
}
i*j*k == n
的count。然后数据量太大,考虑优化。#include
using namespace std;
typedef long long ll;
vector<ll> vv;
ll n = 2021041820210418;
ll ans = 0;
int main()
{
for(ll i = 1 ; i < sqrt(n) ; i ++ )
{
if(n % i == 0)
{
vv.push_back(i);
if(n / i != i)
vv.push_back(n / i);
}
}
int len = vv.size();
for(ll i = 0 ; i < len ; i ++ )
for(ll j = 0 ; j < len ; j ++ )
for(ll k = 0 ; k < len ; k ++ )
if(vv[i] * vv[j] * vv[k] == n) ans ++;
cout << ans;
return 0;
}
最大公约数(a, b) = a * b / gcd(a, b)
。#include
using namespace std;
const int N = 2022;
int g[N][N];
int gcd(int x, int y)
{
return x == 0 ? y : gcd(y % x, x);
}
int dist[N];
bool st[N];
int dijkstra()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
for(int i = 1 ; i <= 2021 ; i ++ )
{
int t = -1;
for(int j = 1 ; j <= 2021 ; j ++ )
if(!st[j] && (t == -1 || dist[j] < dist[t]))
t = j;
st[t] = true;
for(int j = 1 ; j <= 2021 ; j ++ )
dist[t] = min(dist[t], dist[j] + g[j][t]);
}
return dist[2021];
}
int main()
{
memset(g, 0x3f, sizeof g);
for(int i = 1 ; i <= 2021 ; i ++ )
for(int j = i + 1 ; j <= 2021 ; j ++ )
{
if(abs(i - j) <= 21)
{
g[i][j] = g[j][i] = i * j / gcd(i, j);
}
}
cout << dijkstra();
return 0;
}
同类题目题解见AcWing 91. 最短Hamilton路径 - AcWing
f[state][j] 表示按state方案走,最终到达j点的所有走法
//881012367360
//集合表示:f[state][j] 表示按state方案走,最终到达j点的所有走法
// 如state = 0001100101,j = 0,则有6种不同走法,CFGA,CGFA,GCFA,GFCA,FGAC,FCGA。(其中第0~n-1个点由对应的A~Z表示)
//属性:count
//初始化:f[1][0] = 1; 表示按state = 000..001时,走到第0个节点的方案是一种,A。(即从0点出发)
//结果,要求从0出发回到0的哈夫曼回路,则需要累加从0出发走所有节点一次后最终停留的节点
//如果需要求从任意点出发,最终回到0的哈夫曼回路,则需要初始化所有可出发点(除去0),然后结果只需要f[(1 << 21)][0]即可
// 反向考虑的话,做法与本题相同
#include
using namespace std;
const int N = 21, M = 1 << N;
bool g[N][N];
long long f[M][N];
int main()
{
for(int i = 1; i <= 21 ; i ++ )
for(int j = 1 ; j <= 21 ; j ++ )
if(__gcd(i, j) == 1) g[i - 1][j - 1] = true;
f[1][0] = 1;
for(int i = 1 ; i < M ; i ++ )
for(int j = 0 ; j < 21 ; j ++ )
if(i >> j & 1)
for(int k = 0 ; k < 21 ; k ++ )
if(g[k][j] && (i >> k & 1))
f[i][j] += f[i - (1 << j)][k];
long long res = 0;
for(int i = 0 ; i <= 20 ; i ++ )
res += f[M - 1][i];
cout << res << '\n';
return 0;
}
#include
using namespace std;
const int N = 100010;
int n, m;
int w[105];
int dp[100010];
int main()
{
cin >> n;
for(int i = 1; i <= n ; i ++ )
{
cin >> w[i];
m += w[i];
}
dp[0] = 1;
for(int i = 1 ; i <= n ; i ++ )
for(int j = m ; j >= 0 ; j -- )
{
dp[j] = dp[j] || dp[abs(j - w[i])];
if(j + w[i] <= m) dp[j] = dp[j] || dp[j + w[i]];
}
int ans = 0;
for(int i = 1 ; i <= m ; i ++ )
ans += dp[i];
cout << ans;
return 0;
}
one | zero | 决策 |
---|---|---|
偶数 | 随便 | 下一位做决定 |
1 | 随便 | 先手胜利 |
大于1的奇数 | 偶数 | 先手胜利 |
大于1的奇数 | 奇数 | 后手胜利 |
#include
#include
#include
using namespace std;
const int N = 2e5 + 10;
int main()
{
int T;
cin >> T;
while(T -- )
{
int n;
int a[N];
cin >> n;
int sum = 0;
for(int i = 0 ; i < n ; i ++ )
{
cin >> a[i];
sum ^= a[i];
}
if(sum == 0)
{
puts("0");
continue;
}
for(int j = 20 ; j >= 0 ; j -- )
{
int one = 0, zero = 0;
for(int i = 0 ; i < n ; i ++ )
{
if(a[i] >> j & 1) one ++;
else zero ++;
}
if(one % 2 == 1)
{
if(zero % 2 == 1 && one != 1) puts("-1");
else puts("1");
break;
}
}
}
return 0;
}
#include
#include
#include
using namespace std;
const int N = 1e5 + 10;
int n;
int h[N], e[N], ne[N], idx, s[N];
int dp[N];
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u, int far)
{
int ans = 0;
for(int i = h[u] ; i != -1 ; i = ne[i])
{
int j = e[i];
if(j == far) continue;
dfs(j, u);
ans = max(ans, dp[j] + 1);
}
//寻找兄弟节点需要注意细节问题
//1.根节点:0
//2.一层节点:父节点出边数 - 1
//3.其他节点:父节点出边数 - 2
//ps:为何减2?(父节点的父节点也算父节点的出边)
int cnt = 0;
if(far)
for(int i = h[far] ; i != -1 ; i = ne[i] )
if(e[i] > far && e[i] != u) cnt ++;
dp[u] = ans + cnt;
}
int main()
{
memset(h, -1, sizeof h);
cin >> n;
for(int i = 2 ; i <= n ; i ++ )
{
int a;
cin >> a;
add(i, a), add(a, i);
}
dfs(1, 0);
cout << dp[1] << '\n';
return 0;
}
详细讲解见:AcWing 3420. 括号序列 - AcWing
#include
using namespace std;
typedef long long ll;
const int N = 5010, mod = 1e9 + 7;
int n;
char str[N];
ll f[N][N];
ll solve()
{
memset(f, 0, sizeof f);
f[0][0] = 1;
for(int i = 1 ; i <= n ; i ++ )
if(str[i] == '(')
{
for(int j = 1 ; j <= n ; j ++ )
f[i][j] = f[i - 1][j - 1];
}
else
{
f[i][0] = (f[i - 1][0] + f[i - 1][1]) % mod;
for(int j = 1 ; j <= n ; j ++ )
f[i][j] = (f[i - 1][j + 1] + f[i][j - 1]) % mod;
}
for(int i = 0 ; i <= n ; i ++ )
if(f[n][i])
return f[n][i];
return -1;
}
int main()
{
cin >> str + 1;
n = strlen(str + 1);
ll l = solve();
reverse(str + 1, str + n + 1);
for(int i = 1 ; i <= n ; i ++ )
if(str[i] == '(') str[i] = ')';
else str[i] = '(';
ll r = solve();
cout << l * r % mod << "\n";
return 0;
}