A Q老师与石头剪刀布
思路
- 对方若出剪刀,那么有石头出石头,没有石头用’$'标记这一局的出手
- 对方若出石头,那么有布出布,没有布用’$'标记这一局的出手
- 对方若出布,那么有剪刀出剪刀,没有剪刀用’$'标记这一局的出手
- 这样的话,所有的石头都尽量拿来对付对方的剪刀,所有的布都尽量拿来对付对方的石头,所有的剪刀都尽量拿来对付对方的布,赢局最多。
- 对于’ $ ‘标记的出手,在输出的时候还剩了什么就出什么,即若当前输出的对局出手是’ $ ',a个石头,b个剪刀,c个布还剩了什么就输出什么。
总结
一开始想的是,对方若出石头,那么Q老师有布出布,无布出石头,再无布出剪刀,依次类推。但是这种方法中前面的出牌会导致后面本来可以为胜局的无法成胜局。例如对方出布,Q老师当前有1个布1个石头,按照刚才的顺序是出布;若对方下次出石头,Q老师当前只有1石头,故只能出石头。这两句Q老师都没有赢,但若第一局出石头,第二局出布,两句中能赢一局。
这个方法失败的原因是若本局不能赢,那么平局和输局对当前的胜局数是等价的,故不能通过指定出手来制造先平局再考虑输局。
代码
#include<iostream>
#include<string>
using namespace std;
int t = 0, n = 0, sumR = 0, sumP = 0, sumS = 0, win = 0;
int main() {
cin >> t;
while (t--) {
win = 0;
string ans;
string s;
cin >> n;
cin >> sumR >> sumP >> sumS;
cin >> s;
for (int i = 0; i < s.size(); i++) {
switch (s[i])
{
case 'R'://石头
if (sumP > 0) {//布
ans.push_back('P');
sumP--;
win++;
}
else ans.push_back('$');
break;
case 'P':
if (sumS > 0) {
ans.push_back('S');
sumS--;
win++;
}
else ans.push_back('$');
break;
case 'S':
if (sumR > 0) {
ans.push_back('R');
sumR--;
win++;
}
else ans.push_back('$');
break;
default:
break;
}
}
if (win >= (n + 1) / 2) {
cout << "YES" << endl;
for (int i = 0; i < ans.size(); i++) {
if (ans[i] == '$') {
if (sumR-- > 0) cout << 'R';
else if (sumP-- > 0) cout << 'P';
else if (sumS-- > 0) cout << 'S';
}
else cout << ans[i];
}
cout << endl;
}
else cout << "NO" << endl;
}
return 0;
}
B Q老师与十字叉
Input
9
5 5
..*..
..*..
*****
..*..
..*..
3 4
****
.*..
.*..
4 3
***
*..
*..
*..
5 5
*****
*.*.*
*****
..*.*
..***
1 4
****
5 5
.....
..*..
.***.
..*..
.....
5 3
...
.*.
.*.
***
.*.
3 3
.*.
*.*
.*.
4 4
*.**
....
*.**
*.**
Output
0
0
0
0
0
4
1
1
2
思路
- 十字是对于某一行和某一列而言的,该行和该列中共有x个白方格,即对于该十字需要x分钟才能构造完成。
- 故记录使用一维数组记录row每一行的白方格数,使用一维数组col记录每一列的白方格数。
- 在计算i行+j列的白方格数是,不能简单地利用row[i]和col[j]相加,因为有可能在整个网格的(i, j)处是白方格,那么使用row[i]和row[j]相加会多加一次这个(i, j)处的白方格。
- 故使用vector进行记录,若(i,j)处是白点,那么vec[i].push_back(j), 这样一来在对i行j列进行计算白方格数时,若vec[i]里有j,那么白方格数为row[i]+col[j]-1。
- 对每行遍历每列,计算的该行和该列中的白方格数,取min拿最小白方格数,若过程中有某行和某列的白方格数是0,那么可以停止计算了,因为最小的值就是0。
总结
在本题当中,需要注意计算i行和j列组成的十字时,不能简单地以第i行和第j列的白方格数相加,要考虑(i,j)处是否是白方格,是否有加两次该位置的白方格。
代码
#include<iostream>
#include<algorithm>
#include<vector>
#include<string.h>
using namespace std;
const int max_num = 5 * 1E4+10;
int row[max_num], col[max_num];
vector<int> vec[max_num];
int main() {
int q, n, m;
cin >> q;
while (q--) {
cin >> n >> m;
char tmp;
memset(row, 0, sizeof(row));
memset(col, 0, sizeof(col));
for (int i = 0; i < n; i++) vec[i].clear();
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> tmp;
if (tmp == '.') {//白色
vec[i].push_back(j);
row[i]++;
col[j]++;
}
}
}
int ans = INT_MAX;
int tag = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
int now = row[i] + col[j];
vector<int>::iterator ret;
ret = find(vec[i].begin(), vec[i].end(), j);
if (ret != vec[i].end()) {
now--;
}
if (now == 0) {
tag = 1;
break;
}
ans = min(now, ans);
}
}
if (tag == 1)
cout << "0" << endl;
else cout << ans << endl;
}
return 0;
}
C Q老师的考验
思路
- 利用矩阵快速幂模板
- 转移矩阵
对于f(0)到f(9)的值为0到9
故该转移矩阵的k-9次幂,再乘矩阵
最后取结果矩阵的(0, 0)即为答案。 - 在得到转移矩阵的k-9次幂后,与上图矩阵相乘只需要取(0,0),故只需要转移矩阵的k-9次幂的第0行与上图矩阵第0列,对应相乘再累加。
代码
#include<iostream>
#include<string.h>
using namespace std;
const int n = 10;
long long k, p;
struct Matrix
{
long long x[n][n];
Matrix operator* (const Matrix& b) const{
Matrix ret;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
ret.x[i][j] = 0;
for (int k = 0; k < n; k++) {
ret.x[i][j] += (x[i][k] * b.x[k][j])%p;
ret.x[i][j] %= p;
}
}
}
return ret;
}
Matrix() {
memset(x, 0, sizeof(x));
}
Matrix(const Matrix& b) {
memcpy(x, b.x, sizeof(x));
}
};
Matrix quick_pow(Matrix b,int pow_num) {
Matrix ret;
for (int i = 0; i < n; i++) ret.x[i][i] = 1;
while (pow_num) {
if (pow_num & 1) ret = ret * b;
b = b * b;
pow_num >>= 1;
}
return ret;
}
int main() {
while (cin >> k >> p) {
Matrix b;
for (int i = 1; i < n; i++) b.x[i][i - 1]=1;
for (int i = 0; i < n; i++) cin >> b.x[0][i];
Matrix res = quick_pow(b, k - 9);
long long ans = 0;
for (int i = 0; i < n; i++) {
ans += res.x[0][i] * (9 - i);
ans %= p;
}
cout << ans << endl;
}
return 0;
}
D Q老师染砖
思路
#include<iostream>
using namespace std;
const int n = 3;
long long p = 10007;
int T = 0, N = 0;
struct Matrix
{
long long x[n][n];
Matrix operator* (const Matrix& b) const {
Matrix ret;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
ret.x[i][j] = 0;
for (int k = 0; k < n; k++) {
ret.x[i][j] += (x[i][k] * b.x[k][j]) % p;
ret.x[i][j] %= p;
}
}
}
return ret;
}
Matrix() {
memset(x, 0, sizeof(x));
}
Matrix(const Matrix& b) {
memcpy(x, b.x, sizeof(x));
}
};
Matrix quick_pow(Matrix b, int pow_num) {
Matrix ret;
for (int i = 0; i < n; i++) ret.x[i][i] = 1;
while (pow_num) {
if (pow_num & 1) ret = ret * b;
b = b * b;
pow_num >>= 1;
}
return ret;
}
int main() {
cin >> T;
while (T--) {
cin >> N;
Matrix b;
b.x[0][0] = 2, b.x[0][1] = 0, b.x[0][2] = 1;
b.x[1][0] = 0, b.x[1][1] = 2, b.x[1][2] = 1;
b.x[2][0] = 2, b.x[2][1] = 2, b.x[2][2] = 2;
Matrix res = quick_pow(b, N);
cout << res.x[0][0] << endl;
}
return 0;
}
E Q老师度假
思路
代码
#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
using namespace std;
const int N = 100 + 5;
int n = 0;
struct Matrix
{
long long x[N][N];
Matrix operator* (const Matrix& b) const {
Matrix ret;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
ret.x[i][j] = 0;
for (int k = 0; k < n; k++) {
ret.x[i][j] = max(ret.x[i][j], x[i][k] + b.x[k][j]);
}
}
}
return ret;
}
Matrix() {
memset(x, 0, sizeof(x));
}
Matrix(const Matrix& b) {
memcpy(x, b.x, sizeof(x));
}
};
Matrix quick_pow(Matrix b, int pow_num) {
Matrix ret;
while (pow_num) {
if (pow_num & 1) ret = ret * b;
b = b * b;
pow_num >>= 1;
}
return ret;
}
int main() {
int len = 0;
while (scanf("%d %d",&len,&n)!=EOF) {
Matrix b;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
scanf("%lld",&b.x[i][j]);
Matrix res = quick_pow(b, len-1);
long long ans = 0;
for (int i = 0; i < n; i++) {
for(int j=0;j < n;j++)
ans = max(ans, res.x[i][j]);
}
printf("%lld\n",ans);
}
return 0;
}