2021年“图森未来杯”全国程序设计邀请赛(校外组)A B(仅思路讨论) J
https://acm.ecnu.edu.cn/contest/383/
这场真的心态有点炸
btw自己码太差了各种看错打错被评测都能搞心态呜,真的该多练练(你每次就说说不做可不好
A - Abstract Algebra
题意:
给
一
个
二
维
矩
阵
X
=
[
a
b
c
d
]
,
再
给
A
=
[
1
1
0
1
]
,
B
=
[
0
1
−
1
0
]
,
给一个二维矩阵 X=\left[ \begin{matrix} a& b\\ c& d\\ \end{matrix} \right], 再给A=\left[ \begin{matrix} 1& 1\\ 0& 1\\ \end{matrix} \right], B=\left[ \begin{matrix} 0& 1\\ -1& 0\\ \end{matrix} \right],
给一个二维矩阵X=[acbd],再给A=[1011],B=[0−110],
保证abcd = 0, ad - bc = 1 ,用A和B构造出X
abcd都是整数
思路:
abcd都是整数并且有一个是0,剩下一定都是1或-1
A
b
=
[
1
b
0
1
]
,
B
2
A
−
b
=
[
−
1
b
0
−
1
]
A^b=\left[ \begin{matrix} 1& b\\ 0& 1\\ \end{matrix} \right], B^2A^{-b} = \left[ \begin{matrix} -1& b\\ 0& -1\\ \end{matrix} \right]
Ab=[10b1],B2A−b=[−10b−1]
[ 0 b c d ] = B − 1 [ c d 0 − b ] , [ a 0 c d ] = B − 1 [ − d c 0 − b ] B − 1 , [ a b c 0 ] = [ − b a 0 c ] B − 1 , \left[ \begin{matrix} 0& b\\ c& d\\ \end{matrix} \right] = B^{-1} \left[ \begin{matrix} c& d\\ 0& -b\\ \end{matrix} \right],\\ \left[ \begin{matrix} a& 0\\ c& d\\ \end{matrix} \right] = B^{-1} \left[ \begin{matrix} -d& c\\ 0& -b\\ \end{matrix} \right]B^{-1},\\ \left[ \begin{matrix} a& b\\ c& 0\\ \end{matrix} \right] = \left[ \begin{matrix} -b& a\\ 0& c\\ \end{matrix} \right] B^{-1}, [0cbd]=B−1[c0d−b],[ac0d]=B−1[−d0c−b]B−1,[acb0]=[−b0ac]B−1,
code :
#include <bits/stdc++.h>
using namespace std;
int main() {
int T;
cin >> T;
while (T--) {
int a, b, c, d;
cin >> a >> b >> c >> d;
if (c == 0) {
if (a == 1) {
cout << 1 << endl;
cout << "A " << b << endl;
} else {
cout << 2 << endl;
cout << "B " << 2 << endl;
cout << "A " << -b << endl;
}
} else if (a == 0) {
if (c == 1) {
cout << 2<< endl;
cout << "B " << -1 << endl;
cout << "A " << d << endl;
} else {
cout << 3 << endl;
cout << "B " << -1 << endl;
cout << "B " << 2 << endl;
cout << "A " << -d << endl;
}
} else if (b == 0) {
if(-d == 1) {
cout << 3 << endl;
cout << "B " << -1 << endl;
cout << "A " << c << endl;
cout << "B " << -1 << endl;
}
else {
cout << 4 << endl;
cout << "B " << -1 << endl;
cout << "B " << 2<< endl;
cout << "A " << -c << endl;
cout << "B " << -1 << endl;
}
}
else if(d == 0) {
if(-b == 1) {
cout << 2 << endl;
cout << "A " << a << endl;
cout << "B " << -1 << endl;
}
else {
cout << 3 << endl;
cout << "B " << 2 << endl;
cout << "A " << -a << endl;
cout << "B " << -1 << endl;
}
}
}
return 0;
}
B - Bracelet(没A
题意:
有一个串是按1234…910111213… 的方式增长的,问要出现给定的子串的时候原串增长到几
思路:
感觉这题思路还挺清楚(就是我代码实在太差了呜
子串长度小于18,于是直接枚举其中的子串截出来作为一个数然后左右扩展扩展到比给定的串长的时候看他是否包含了给出的串
另外还有情况是前面半段是一个数的后半段后面半段是后一个数的前半段,例如:9990,这种情况就截出来然后前面+1,看是否有进位(若有进位则裁掉)再接到后面那半段上面去(9990: 99->00 ,90+00 去掉共同部分->900
有种自己在写大(小?)模拟的错觉 ,我死, 一直wa2,放着不想动了呜
是读完题就觉得可做然后一直卡,心态快没了,绝了我配写模拟题吗
我处刑我自己.jpg (如果有人看出来了麻烦告诉我感激不尽
code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int cmp(string a, string b) {
if (a == b) return 0;
int lena = a.size();
int lenb = b.size();
if (lena < lenb) return -1;
if (lena > lenb) return 1;
return (a < b) ? -1 : 1;
}
inline ll toll(string s) {
ll res = 0;
int len = s.size();
for (int i = 0; i < len; ++i) {
res = res * 10 + (s[i] - '0');
}
return res;
}
inline string toString(ll x) {
string res = "";
ll tmp = x;
while (tmp) {
char ch = '0' + tmp % 10;
res = ch + res;
tmp /= 10;
}
return res;
}
string ans = "";
inline void solve(string s) {
int len = s.size();
for (int i = 1; i < len; ++i) {
for (int j = 0; j + i <= len; ++j) {
string tmp = s.substr(j, i);
ll pp = toll(tmp);
ll qian = j, hou = len - j - i;
ll x = pp;
bool f = 1;
while (qian > 0) {
x--;
if (x < 0) {
f = 0;
break;
}
string ttt = toString(x);
qian -= ttt.size();
tmp = ttt + tmp;
}
if (!f) continue;
x = pp;
while (hou > 0) {
x++;
string ttt = toString(x);
hou -= ttt.size();
tmp = tmp + ttt;
}
// cout << "----- "<< tmp << endl;
if (tmp.find(s) != string::npos) {
string nwans = toString(x);
if (cmp(nwans, ans) < 0) {
ans = nwans;
}
}
}
}
}
inline string add1(string s) {
long long res = 0;
int len = s.size();
for (int i = 0; i < len; ++i) {
res = res * 10 + (s[i] - '0');
}
res++;
string t = "";
while (res) {
char ch = res % 10 + '0';
t = ch + t;
res /= 10;
}
return t;
}
inline string getString(string a, string b) {
reverse(a.begin(), a.end());
int len = min(a.size(), b.size());
int pos = 0;
for (int i = 0; i < len; ++i) {
if (a[i] != b[i]) {
pos = i;
break;
}
}
reverse(a.begin(), a.end());
string res = a + b.substr(pos);
return res;
}
int main() {
int T;
cin >> T;
while (T--) {
string s;
cin >> s;
ans = s;
solve(s);
int len = s.size();
// for (int i = 1; i < len; ++i) {
// if (s[i] == '0') continue;
// string tmp = s.substr(i);
// tmp = tmp + s.substr(0, i);
// tmp = add1(tmp);
// if (cmp(ans, tmp) > 0) {
// ans = tmp;
// }
// }
for (int i = 1; i < len; ++i) {
string b = s.substr(i);
string a = s.substr(0, i);
string aa = add1(a);
if (aa.size() > a.size()) {
aa = aa.substr(1);
}
string c = getString(b, aa);
if (c[0] == '0') continue;
if (cmp(ans, c) > 0) {
ans = c;
}
}
cout << ans << endl;
}
}
J - Just the Chosen One
题意: 一共有n个人,每个人依次抽取数字,数字前m的可以获得一份礼物,问第K个人期望获得的礼物数
第 i 轮会获得礼物的概率是 m i \frac{m}{i} im
调和级数求和,但是直接扫时间不够
当n比较大的时候, ∑ i = 1 n 1 i \sum_{i = 1}^{n} \frac{1}{i} ∑i=1ni1 ~ l n n lnn lnn
前缀和减一下就行
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
double m, k, n;
cin >> n >> m >> k;
double res = 0;
if (k < m) {
res += m - k;
k = m;
}
if (n < (int) (1e7)) {
double sum = 0;
for (int i = k; i <= n; ++i) {
sum += 1.0 / (double) i;
}
res += sum * m;
} else res += (log(n) - log(k - 1.0)) * m;
cout << fixed << setprecision(10) << res << endl;
return 0;
}