【CCF CAT 】全国算法精英大赛2024年2月1日
赛时我们通过了7题,排名25。
A 摩斯电码
队友代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int, int> P;
map<string, string> mp;
void solve () {
mp["01"] = "A";
mp["1000"] = "B";
mp["1010"] = "C";
mp["100"] = "D";
mp["0"] = "E";
mp["0010"] = "F";
mp["110"] = "G";
mp["0000"] = "H";
mp["00"] = "I";
mp["0111"] = "J";
mp["101"] = "K";
mp["0100"] = "L";
mp["11"] = "M";
///////
mp["10"] = "N";
mp["111"] = "O";
mp["0110"] = "P";
mp["1101"] = "Q";
mp["010"] = "R";
mp["000"] = "S";
mp["1"] = "T";
mp["001"] = "U";
mp["0001"] = "V";
mp["011"] = "W";
mp["1001"] = "X";
mp["1011"] = "Y";
mp["1100"] = "Z";
///////
mp["01111"] = "1";
mp["00111"] = "2";
mp["00011"] = "3";
mp["00001"] = "4";
mp["00000"] = "5";
mp["10000"] = "6";
mp["11000"] = "7";
mp["11100"] = "8";
mp["11110"] = "9";
mp["11111"] = "0";
mp["001100"] = "?";
mp["10010"] = "/";
mp["101101"] = "()";
mp["100001"] = "-";
mp["010101"] = ".";
string s;
cin >> s;
vector<string> v;
for(int i = 0; i < s.size(); i++) {
string t;
int j = i;
while(j < s.size() && s[j] != '.') {
t += s[j];
j ++ ;
}
// cout << t << ": " << mp[t] << endl;
v.emplace_back(mp[t]);
i = j;
}
for(auto & x : v) {
cout << x;
}
}
signed main () {
solve ();
return 0;
}
B 光线折射
多画一画,多特批一下就行了
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
i32 main() {
int n, m;
cin >> n >> m;
int d, x = 0, y = 0;
if (n < m) {
x = n, y = n;
d = min(n, m - n);
x -= d, y += d;
if (x != 0) y -= x, x = 0;
else if (x == 0 and y == m) x += d, y -= d;
else {
d = min(n, m - y);
x += d, y += d;
}
} else if (n > m) {
x = m, y = m;
d = min(n - m, m);
x += d, y -= d;
if (y != 0) {
x -= y, y = 0;
} else if (x == n and y == 0) x -= d, y += d;
else {
d = min(m, n - x);
x += d, y += d;
}
} else x = n, y = m;
cout << x << " " << y << "\n";
return 0;
}
C 多项式还原
题目保证了有唯一解,所以可以把\(m\)转换成\(n+1\)进制数。这个思路是队友想的。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, m;
cin >> n >> m;
int t = n + 1;
vi a;
while (m)
a.push_back(m % t), m /= t;
int f = 0;
for (int i = a.size() - 1; i >= 0; i--) {
if (a[i] == 0) continue;
if (f == 1) cout << "+";
else f = 1;
if (a[i] != 1 or i == 0) cout << a[i];
if (i == 1) cout << "x";
else if (i > 1) cout << "x^" << i;
}
return 0;
}
D 开心消消乐
\(n,m\)都很小,所以可以直接暴力搜索。为了方便处理,我把整个图旋转一下,来改变重力的方向。
对于当前的状态,直接bfs染色,同时统计每种颜色出现的次数。然后枚举每个个数大于等于3的连通块。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
int n, m, res = 0;
void dfs(vector<vi> g) {
int ans = n * m;
vector<vi> col;
vi cnt;
cnt.push_back(-1);
for (auto it: g)
ans -= it.size(), col.emplace_back(it.size(), 0);
res = max(res, ans);
for (int i = 0, t = 0; i < m; i++) {
for (int j = 0; j < g[i].size(); j++) {
if (col[i][j]) continue;
t++, cnt.push_back(0);
queue<pii> q;
q.emplace(i, j);
for (int x, y; not q.empty();) {
auto _ = q.front();
x = _.first, y = _.second, q.pop();
if (col[x][y]) continue;
col[x][y] = t, cnt[t]++;
for (int l = 0, fx, fy; l < 4; l++) {
fx = x + dx[l], fy = y + dy[l];
if (fx < 0 or fx >= m) continue;
if (fy < 0 or fy >= g[fx].size()) continue;
if (col[fx][fy] or g[fx][fy] != g[x][y]) continue;
q.emplace(fx, fy);
}
}
}
}
for (int l = 1; l < cnt.size(); l++) {
if (cnt[l] < 3) continue;
vector<vi> ng(m);
for (int j = 0; j < m; j++) {
for (int i = 0; i < col[j].size(); i++) {
if (col[j][i] == l) continue;
ng[j].push_back(g[j][i]);
}
}
dfs(ng);
}
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
cin >> n >> m;
vector<vi> g(m, vi(n));
for (int i = 1, x; i <= n; i++)
for (int j = 0; j < m; j++)
cin >> g[j][n - i];
dfs(g);
cout << res << "\n";
return 0;
}
E 等式
队友代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int, int> P;
typedef long long ll;
vector<int> minp(20000001), primes;
int m = 2e7;
void init(vector<int> & minp, vector<int> & primes, int m) {
for(int i = 2; i <= m; i++) {
if(!minp[i]) {
minp[i] = i;
primes.emplace_back(i);
}
for(auto & p : primes) {
int n = i * p;
if(n > m) break;
minp[n] = p;
if(minp[i] == p) {
break;
}
}
}
}
void solve () {
int n;
cin >> n;
ll ans = 0;
for(auto & p : primes) {
if(p >= n) break;
int now = n - p;
if(minp[now] == now) continue;
unordered_map<int, int> mp;
while(now > 1) {
mp[minp[now]] ++ ;
now /= minp[now];
}
int sum = 1;
for(auto & [x, y] : mp) {
sum *= (y + 1);
}
ans += sum;
}
cout << ans << endl;
}
signed main () {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
init(minp, primes, m);
solve ();
return 0;
}
F 放大灯
G 航海
首先我们储存的时候可以直接存\(c_i=c_i-a_i\)表示盈利。
\(dfs(x,m,w,ans)\)表示移动到\(x\),剩余本金\(m\),剩余载重\(w\),当前最大盈利\(ans\)
然后我们只要枚举子节点,枚举选不选即可。
直接暴搜,还是不太行的,要维护\(f[x][m][w]\)做一个最优性剪枝和记忆法。
这样搜索已经算很接近了,再加一个\(c_i<=0\)时一定不选即可。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
//#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
const int inf = 1e9;
vi a, b, c, vis;
vector<vi> e;
vector<vector<vi>> f;
int n, res = 0;
void dfs(int x, int m, int w, int ans) {
if (f[x][m][w] >= ans) return;
f[x][m][w] = ans, res = max(res, ans);
if (x == n) return;
if (vis[x] == 0 and m >= a[x] and w >= b[x] and c[x] > 0) { // 可以购买
vis[x] = 1;
for (auto y: e[x])
dfs(y, m - a[x], w - b[x], ans + c[x]);
vis[x] = 0;
}
for (auto y: e[x]) // 不买
dfs(y, m, w, ans);
return;
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int m, v, x;
cin >> n >> m >> v >> x;
a.resize(n), b.resize(n), c.resize(n);
vis.resize(n);
e.resize(n);
f = vector<vector<vi>>(n + 1, vector<vi>(m + 1, vi(v + 1, -inf)));
for (int i = 1, t; i < n; i++) {
cin >> a[i] >> b[i] >> c[i] >> t;
c[i] -= a[i], e[i].resize(t);
for (auto &j: e[i]) cin >> j;
}
dfs(x, m, v, 0);
cout << res << "\n";
return 0;
}
H 火山喷发
思路就是进行bfs,在过程种判断有没有接触到大海,以及所有接触到的墙壁。
当队列为空时,判断有没有接触到大海,如果接触到就结束,如果没有就把墙壁重新入队,再进行搜索就好。
队友代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=100+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
void solve() {
int n,m,k,now;
cin>>n>>m>>k;
now=n*m;
vector<vector<int>>g(n+5,vector<int>(m+5));
vector<vector<int>>st(n+5,vector<int>(m+5));
while(k--){
int x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
if(x1>x2)swap(x1,x2);
if(y1>y2)swap(y1,y2);
for(int i=x1;i<=x2;++i)
for(int j=y1;j<=y2;++j){
if(!g[i][j])now--;
g[i][j]=1;
}
}
//207
// cout<<now<<'\n';
int sx,sy;
cin>>sx>>sy;
queue<PII>q,wal;
q.push({sx,sy});
st[sx][sy]=1;
bool ok=true;
while(1){
while(q.size()){
auto t=q.front();q.pop();
if(g[t.first][t.second]!=1)now--;
for(int i=0;i<4;++i){
int x=t.first+dx[i],y=t.second+dy[i];
if(x<1||x>n||y<1||y>m) {
ok = false;
}else{
if(!st[x][y]){
if(g[x][y]==1)wal.push({x,y});
else q.push({x,y});
st[x][y]=1;
}
}
}
}
// cout<<now<<'\n';
if(ok&&now>0){
while(wal.size()){
auto t=wal.front();wal.pop();
int x=t.first,y=t.second;
// g[x][y]=0;
q.push({x,y});
st[x][y]=1;
}
}else break;
}
cout<<now;
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
// cin>>t;
while(t--){
solve();
}
return 0;
}