LINK
A. Fried Fish
思路
- 注意 n < = k n <= k n<=k 的时候答案是 2 2 2
AC(ez)
#include <bits/stdc++.h>
using namespace std;
int main(){
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n, k;
cin >> n >> k;
if (n <= k) cout << 2 << endl;
else if (n * 2 % k) cout << 2 * n / k + 1 << endl;
else cout << 2 * n / k << endl;
return 0;
}
B. Hanoi tower
思路
根据之前的汉诺塔模型推断就可以,原来的汉诺塔模型是
2
n
−
1
2^n - 1
2n−1
如果输入是
3
n
3n
3n
如果
n
n
n 是奇数:
2
2
n
−
1
+
2
n
−
2
2^{2n-1}+2^n-2
22n−1+2n−2
如果
n
n
n 是偶数:
2
2
n
−
1
+
2
n
−
1
−
1
2^{2n-1} + 2^{n-1} - 1
22n−1+2n−1−1
AC(高精度 + 递归)
#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
int ans[N], par1[N], par2[N];
int main(){
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n;
cin >> n;
n /= 3;
par1[1] = par2[1] = 1;
int len1 = 1, len2 = 1;
for (int i = 1; i <= n; i ++ ) {
for (int j = 1; j <= len1; j ++ )
par1[j] *= 2;
for (int j = 1; j <= len1; j ++ ) {
par1[j + 1] += par1[j] / 10;
par1[j] %= 10;
}
while (par1[len1 + 1]) {
len1 ++;
par1[len1 + 1] += par1[len1] / 10;
par1[len1] %= 10;
}
}
for (int i = 1; i < n; i ++ ) {
for (int j = 1; j <= len2; j ++ )
par2[j] *= 2;
for (int j = 1; j <= len2; j ++ ) {
par2[j + 1] += par2[j] / 10;
par2[j] %= 10;
}
while (par2[len2 + 1]) {
len2 ++;
par2[len2 + 1] += par2[len2] / 10;
par2[len2] %= 10;
}
}
for (int i = 1; i <= len1; i ++ )
for (int j = 1; j <= len2; j ++ )
ans[i + j - 1] += par1[i] * par2[j];
for (int i = 1; i <= len1 + len2 - 1; i ++ ) {
ans[i + 1] += ans[i] / 10;
ans[i] %= 10;
}
int len = len1 + len2 - 1;
while (ans[len + 1]) {
len ++;
ans[len + 1] += ans[len] / 10;
ans[len] %= 10;
}
if (n & 1) {
for (int i = 1; i <= len1; i ++ )
ans[i] += par1[i];
for (int i = 1; i <= len; i ++ ) {
ans[i + 1] += ans[i] / 10;
ans[i] %= 10;
}
while (ans[len + 1]) {
len ++;
ans[len + 1] += ans[len] / 10;
ans[len] %= 10;
}
ans[1] -= 2;
if (ans[1] < 0) {
int k = 1;
while (k <= len && ans[k] < 0) {
ans[k] += 10;
ans[k + 1] --;
k ++;
}
if (k == len && ans[k] == 0) len --;
}
} else {
for (int i = 1; i <= len2; i ++ )
ans[i] += par2[i];
for (int i = 1; i <= len; i ++ ) {
ans[i + 1] += ans[i] / 10;
ans[i] %= 10;
}
while (ans[len + 1]) {
len ++;
ans[len + 1] += ans[len] / 10;
ans[len] %= 10;
}
ans[1] --;
if (ans[1] < 0) {
int k = 1;
while (k <= len && ans[k] < 0) {
ans[k] += 10;
ans[k + 1] --;
k ++;
}
if (k == len && ans[k] == 0) len --;
}
}
for (int i = len; i >= 1; i -- ) cout << ans[i];
cout << endl;
return 0;
}
D. Weather Station
思路
- 快速幂
AC(ez)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 1e9 + 7;
LL qmi(int a, int q) {
LL tmp = a;
LL ans = 1;
while (q) {
if (q & 1) ans = ans * tmp % mod;
tmp = tmp * tmp % mod;
q >>= 1;
}
return ans;
}
int main(){
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
string s;
cin >> s;
int len = s.size();
int q = 0;
for (int i = 1; i < len; i ++ ) {
if (s[i] == 'E' && (s[i - 1] == 'N' || s[i - 1] == 'S')) q ++;
if (s[i] == 'W' && (s[i - 1] == 'N' || s[i - 1] == 'S')) q ++;
}
cout << qmi(2, q);
return 0;
}
E. Cupcakes
思路
- 挺简单的, 就是模拟一遍就能过
- p r e m n premn premn 就是在某论贪心的同学之前所有同学吃的最小值
- p r e m x premx premx 就是在某论贪心的同学之前所有同学吃的最大值
- p o s pos pos 就是贪心同学的位置
- m x mx mx 就是贪心的同学的 a [ i ] a[i] a[i]
- s u m sum sum 储存一轮除了贪心的同学, 剩下同学吃的最大值
细节注释
- 注释1:为什么是 k − = m x k -= mx k−=mx 因为贪心的同学遇到蛋糕就是全吃, 所以如果这轮不能结束游戏, 那么贪心的同学会全部吃完, 把 k k k 卡在 p r e m n premn premn 和 p r e m x premx premx 之间, 就是看, 以这两种极端的情况为标准, 判断能不能, 让除了被贪心同学吃的蛋糕, 被剩下的同学分完
AC(模拟)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int a[N];
int main(){
freopen("INPUT.TXT", "r", stdin);
freopen("OUTPUT.TXT", "w", stdout);
int n, k;
scanf("%d%d", &n, &k);
int pos, mx = 0;
LL sum = 0;
for (int i = 1; i <= n; i ++ ) {
scanf("%d", a + i);
if (a[i] > mx) {
pos = i;
mx = a[i];
}
sum += a[i];
}
sum -= mx;
LL premn = pos - 1, premx = 0;
for (int i = 1; i < pos; i ++ )
premx += a[i];
while (k >= 0) {
if (k >= premn && k <= premx) { //注释1
puts("YES");
return 0;
}
k -= mx; //注释1
premn += n - 1;
premx += sum;
}
puts("KEK");
return 0;
}
F. Vitamins
思路
- 按并查集分类就可以了, 然后就是按照是否为 R R R 判断, 并将祖宗节点染色, 染色之对于子节点也要染色
细节注释
- 注释1:为什么 = = = 要提前操作, 因为只有 = = = 提前操作就可以把点之间的相同颜色的点就可以归为一类了, 这样子不会影响出现在 = = = 号前面的 < < < 和 > > > , 就可以充分归类了
- 注释2:如果 b i g big big s m a l l small small 都不为空, 证明了该节点就是 R R R, 然后依次取出在 b i g big big 和 s m a l l small small 中储存的祖宗节点染色
- 注释3:把没有染色完全的子节点依次染色, 注意是 f i n d ( p [ i ] ) find(p[i]) find(p[i]), 要找祖宗节点, 不可以只写 p [ i ] p[i] p[i]
总结
- 以后并查集一定要写 f i n d ( p [ i ] ) find(p[i]) find(p[i]), 不可以对 p [ i ] p[i] p[i] 掉以轻心, 因为可能存在根本没有把之后的子节点接到最终的祖宗节点上
AC(并查集)
#include <bits/stdc++.h>
using namespace std;
#define PB push_back
typedef vector<int> VI;
const int N = 1e3 + 10;
int p[N], a[N * N / 2], b[N * N / 2];
char op[N * N / 2], ans[N];
VI big[N], small[N];
int find(int x) {
if (p[x] == x) return x;
return p[x] = find(p[x]);
}
int main(){
freopen("INPUT.TXT", "r", stdin);
freopen("OUTPUT.TXT", "w", stdout);
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ )
p[i] = i, ans[i] = '?';
for (int i = 1; i <= m; i ++ ) {
scanf("%d%c%d", &a[i], &op[i], &b[i]);
if (op[i] == '=') //注释1
p[find(a[i])] = find(b[i]);
}
for (int i = 1; i <= m; i ++ ) {
if (op[i] == '<') {
big[find(a[i])].PB(find(b[i]));
small[find(b[i])].PB(find(a[i]));
} else if (op[i] == '>'){
big[find(b[i])].PB(find(a[i]));
small[find(a[i])].PB(find(b[i]));
}
}
for (int i = 1; i <= n; i ++ ) {
if (big[i].size() > 0 && small[i].size() > 0) { //注释2
ans[i] = 'R';
for (auto t : big[i])
ans[t] = 'W';
for (auto t : small[i])
ans[t] = 'B';
}
}
for (int i = 1; i <= n; i ++ ) {
if (ans[i] == '?')
ans[i] = ans[find(p[i])]; //注释3
}
for (int i = 1; i <= n; i ++ )
printf("%c", ans[i]);
puts("");
return 0;
}
G. Sphenic numbers
思路
- 质数唯一分解定理
AC(ez)
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int ans[N];
int main(){
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n, cnt = 0;
cin >> n;
for (int i = 2; i <= n; i ++ ) {
while (n % i == 0) {
ans[cnt ++] = i;
n /= i;
}
}
if (cnt == 3) {
if (ans[1] != ans[2] && ans[1] != ans[0]) cout << "YES" << endl;
else cout << "NO" << endl;
} else cout << "NO" << endl;
return 0;
}
H. Non-random numbers
思路
- 我们发现只要是大于 9 9 9 的数字就是在 9 9 9 之后补 0 0 0, 因为他只卡前 9 9 9 位, 那么前 9 9 9 个数字就是暴力跑一遍, 直接打表就好
AC(math)
#include <bits/stdc++.h>
using namespace std;
LL ans[10] = {0, 8, 72, 648, 5832, 52488, 472392, 4251528, 38263752, 344373768};
int main(){
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n;
cin >> n;
if (n <= 9) cout << ans[n];
else {
cout << ans[9];
n -= 9;
while (n --)
cout << 0;
}
return 0;
}
J. Architect of Your Own Fortune
思路
AC(二分图)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int mat[105][105];
int at[105][105],ta[105][105];
struct node{
int pre,beh;
}a[105],b[105];
int n,m;
string s1[105],s2[105];
bool vis[N];
int ans[N];
bool dfs(int x){
for(int i=1;i<=m;i++){
if(!vis[i]&&mat[x][i]){
vis[i]=1;
if(!ans[i]||dfs(ans[i])){
ans[i]=x;
return true;
}
}
}
return false;
}
int main(){
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>s1[i];
a[i].pre =s1[i][0]-'0'+s1[i][1]-'0'+s1[i][2]-'0';
a[i].beh =s1[i][3]-'0'+s1[i][4]-'0'+s1[i][5]-'0';
}
for(int i=1;i<=m;i++){
cin>>s2[i];
b[i].pre =s2[i][0]-'0'+s2[i][1]-'0'+s2[i][2]-'0';
b[i].beh =s2[i][3]-'0'+s2[i][4]-'0'+s2[i][5]-'0';
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i].pre ==b[j].beh ){
mat[i][j]=1;
at[i][j]=1;
}
if(a[i].beh ==b[j].pre ){
mat[i][j]=1;
ta[i][j]=1;
}
}
}
int cnt=0;
for(int i=1;i<=n;i++){
memset(vis,0,sizeof(vis));
if(dfs(i))
cnt++;
}
cout<<cnt<<endl;
for(int i=1;i<=m;i++){
if(ans[i]!=0){
int t=ans[i];
if(at[t][i]==1){
cout<<"AT"<<" ";
cout<<s1[t]<<" "<<s2[i]<<endl;
}
else if(ta[t][i]==1){
cout<<"TA"<<" ";
cout<<s2[i]<<" "<<s1[t]<<endl;
}
}
}
return 0;
}