写在前面:写题解只是督促自己补题,写的代码没有炫技成份
A-矩阵转置置
题目:https://ac.nowcoder.com/acm/contest/65507/A
通过题目给出的样例二可以发现,这道题的实质就是让我们对于输入的二维数组,从第N行到第1行,从第N列到第1列,先列后行打印输出。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 110;
int a[N][N];
signed main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= n; j ++)
cin >> a[i][j];
for (int i = n; i >= 1; i --)
{
for (int j = n; j >= 1; j --)
{
cout << a[i][j] << ' ';
}
cout << endl;
}
return 0;
}
B-小红买基金
题目:https://ac.nowcoder.com/acm/contest/65507/B
因为题目中给了买基金的限制,假如可以买的基金有res个,那么这道题的实质就是求,也可以看成是给你res个基金,每个基金有选和不选两种状态,那么
就是答案,只不过因为数据范围,所以要用到快速幂。下面给出1种快速幂,1种用逆元求组合数,1种公式推组合数写法。
快速幂代码
第33行减的0是减掉任何基金都不选的方案数
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int mod = 1e9 + 7;
int quick_pow(int a, int b)
{
int res = 1;
while (b)
{
if (b & 1)
{
res = res * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return res;
}
signed main()
{
cin.tie(0)->sync_with_stdio(0);
int n, a, b;
cin >> n >> a >> b;
int cnt = 0;
for (int i = 1; i <= n; i ++)
{
int x, y;
cin >> x >> y;
if (x >= a && y <= b) cnt ++;
}
int res = quick_pow(2, cnt) - 1;
cout << res << endl;
return 0;
}
逆元求组合数板子
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int mod = 1e9 + 7;
const int N = 2e6 + 10;
int fact[N];//i的阶乘
int infact[N];//i的阶乘的逆元
int quick_pow(int a, int b)
{
int res = 1;
while (b)
{
if (b & 1)
{
res = res * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return res;
}
signed main()
{
cin.tie(0)->sync_with_stdio(0);
fact[0] = infact[0] = 1;
for (int i = 1; i < N; i ++)
{
fact[i] = i * fact[i - 1] % mod;
infact[i] = infact[i - 1] * quick_pow(i, mod - 2) % mod;
}
int n, x, y;
cin >> n >> x >> y;
int res = 0;
for (int i = 1; i <= n; i ++)
{
int a, b;
cin >> a >> b;
if (a >= x && b <= y) res ++;
}
int sum = 0;
for (int i = 1; i <= res; i ++)
{
int k = fact[res] * infact[i] % mod * infact[res - i] % mod;
sum = (sum + k) % mod;
}
cout << sum << endl;
return 0;
}
公式推组合数代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int mod = 1e9 + 7;
int quick_pow(int a, int b)
{
int res = 1;
while (b)
{
if (b & 1)
{
res = res * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return res;
}
signed main()
{
cin.tie(0)->sync_with_stdio(0);
int n, x, y;
cin >> n >> x >> y;
int res = 0;
for (int i = 1; i <= n; i ++)
{
int a, b;
cin >> a >> b;
if (a >= x && b <= y) res ++;
}
int sum = 0;
int last = 1;
for (int i = 1; i <= res; i ++)
{
int now = last * (res - i + 1) % mod * quick_pow(i, mod - 2) % mod;//涉及到除法取模,除以i就是乘i的逆元,也就是quick_pow(i, mod - 2)
last = now;
sum = (sum + now) % mod;
}
cout << sum << endl;
return 0;
}
C-小红的密码修改https://ac.nowcoder.com/acm/contest/65507/C
这道题我们分类讨论一下即可,因为一次只能修改一个字符,我们发现,当我们想修改的这一类字符(比如:数字这一类)的数量大于1个的时候,我们将其修改成任何字符都不会对合法性有影响。因为这一类的数量大于1个,所以总有剩下的字符是合法的,唯一注意的是,我们在修改的时候不能和没改之前一样。这4类字符一共有66个字符,我们以题意为例,数字有5个,所以数字能修改的方案就是5*66-5,其他类字符如此。
当某一类字符只出现一次的时候,比如样例中的a,那么它能修改的范围只有自己这一类,不然会不合法,那么a的修改方案就只有26-1=25种,其他亦如此。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
signed main()
{
cin.tie(0)->sync_with_stdio(0);
int t;
cin >> t;
while (t --)
{
string s;
cin >> s;
int a = 0, b = 0, c = 0, d = 0;
for (int i = 0; i < s.size(); i ++)
{
if (s[i] == '.' || s[i] == ',' || s[i] == '!' || s[i] == '?') a ++;
else if (s[i] - '0' >= 0 && s[i] - '0' <= 9) b ++;
else if (s[i] - 'A' >= 0 && s[i] - 'A' <= 25) c ++;
else d ++;
}
int res = 0;
if (a > 1) res += a * 66 - a;
else res += 3;
if (b > 1) res += b * 66 - b;
else res += 9;
if (c > 1) res += c * 66 - c;
else res += 25;
if (d > 1) res += d * 66 - d;
else res += 25;
cout << res << endl;
}
return 0;
}
D-小红的转账设置方式https://ac.nowcoder.com/acm/contest/65507/D
这道题第一个问题就是建个无向图,然后bfs求一下各个点到1号点的最短距离求和即可。对于第二个问题,咱们慢慢讨论。
首先:什么时候两个点之间的边可以任意方向?
答:情况一:两个点处于同一层,且有连边,如图:
2号点和3号点到1号点的最短距离都是1,连接2和3号点的这条边对两个点的最小值无影响,所以可以任意方向。
情况二:某个点到1号点的最短距离路径不止1条,如图点4。
只是张嘴说的话,这题就这两种情况,但是怎么用代码实现呢?
先看代码,代码中有注释:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
vector<int> g[N];//图
int n, m;
int dist[N];//各个点到1号点的最短距离
void bfs()//bfs求起点1到各个点的最短距离
{
memset(dist, -1, sizeof dist);
dist[1] = 0;
queue<int> q;
q.push(1);
while (q.size())
{
auto p = q.front();
q.pop();
for (auto u : g[p])
{
if (dist[u] != -1) continue;
dist[u] = dist[p] + 1;
q.push(u);
}
}
}
int get_res1()//问题1,每个点的最短距离求和嘛
{
int res = 0;
for (int i = 1; i <= n; i ++) res = (dist[i] + res) % mod;
return res;
}
signed main()
{
cin.tie(0)->sync_with_stdio(0);
cin >> n >> m;
for (int i = 1; i <= m; i ++)//建无向图嘛
{
int a, b;
cin >> a >> b;
g[a].push_back(b);
g[b].push_back(a);
}
bfs();
int res1 = get_res1();//代价之和
int res2 = 1;//第二问的答案
int cnt1 = 0;//存两个点在同一层的边,后面的cnt1/2是因为无向边遍历的时候有重边
for (int i = 2; i <= n; i ++)
{
int c = 0;
for (auto u : g[i])
{
//我们说的第一种情况
if (dist[u] == dist[i]) cnt1 ++;//同一层 两个点之间的边可以乱连 但是有重复的情况
//第二种情况
if (dist[u] == dist[i] - 1) c ++;//说明节点u有更近的路线到1 u和i之间的边可以乱连
}
int res = 1;
for (int j = 1; j <= c; j ++) res = res * 2 % mod;//乘法原理
res = (res - 1 + mod) % mod;//这里减1是因为图中的4号点,你不可能5和2都向4连边涩,那样4号点就出不去了
res2 = res2 * res % mod;//乘法原理 总不可能是加吧
}
for (int i = 1; i <= cnt1 / 2; i ++)
{
res2 = res2 * 2 % mod;//乘法原理
}
cout << res1 << ' ' << res2 << endl;
return 0;
}
E-小红打bosshttps://ac.nowcoder.com/acm/contest/65507/E
欧克,还没补,看其他题解去吧。。。