2023冲刺国赛模拟5
A. 无限之环
不难发现 \(B\) 需要字母集合相同
对于 \(A\) ,需要最后一个 \(B\) 中未出现的字母前完全相同
这里写的用了 \(string\)
实际上为了复杂度的话应该用 \(hash\)
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<string, int> psi;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 1e5 + 55;
int n, cnt;
map<psi, int>mp;
vector<int>ans[maxn];
string a, b;
void print(){
printf("%d\n",cnt);
for(int i = 1; i <= cnt; ++i){
printf("%d ",(int)ans[i].size());
for(int v : ans[i])printf("%d ",v); printf("\n");
}
}
bool vis[maxn];
int main(){
freopen("infty.in","r",stdin);
freopen("infty.out","w",stdout);
ios::sync_with_stdio(false);
cin >> n;
for(int i = 1; i <= n; ++i){
cin >> a >> b; psi res;
int len = b.size(), s = 0;
if(len == 1 && b[0] == '=')--len;
for(int j = 0; j < len; ++j)s |= (1 << (b[j] - 'a'));
res.second = s;
len = a.size();
if(len == 1 && a[0] == '=')res.first = "";
else{
while(len && (s & (1 << (a[len - 1] - 'a'))))--len;
string tmp = ""; for(int j = 0; j < len; ++j)tmp += a[j];
res.first = tmp;
}
if(!mp[res])mp[res] = ++cnt;
ans[mp[res]].push_back(i);
}
print();
return 0;
}
B. 变化多端
搜索。。。
如果马多就移动空格
一种可能的实现是按照顺序枚举马槽,然后搜到马移动
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
vector<pair<pii, pii>>ans;
int dx[8] = {1, 2, 2, 1, -1, -2, -2, -1}, dy[8] = {2, 1, -1, -2, -2, -1, 1, 2};
int n; char s[5];
bool mp[9][9], vis[9][9];
vector<pii>v;
pii pre[9][9];
void move(int ax, int ay, int bx, int by){
swap(mp[ax][ay], mp[bx][by]);
ans.push_back({pii(ax, ay), pii(bx, by)});
}
int rx, ry;
bool dfs(int x, int y){
vis[x][y] = true;
if(mp[x][y]){rx = x; ry = y; return true;}
for(int i = 0; i < 8; ++i){
int nx = x + dx[i], ny = y + dy[i];
if(nx >= 1 && nx <= 8 && ny >= 1 && ny <= 8 && !vis[nx][ny]){
pre[nx][ny] = {x, y};
if(dfs(nx, ny))return true;
}
}
return false;
}
void trans(int i, int j){
v.push_back(pii(i, j));
if(mp[i][j])return;
memset(vis, 0, sizeof(vis));
for(pii x : v)vis[x.first][x.second] = 1;
rx = ry = 0; dfs(i, j);
if(rx){
while(rx != i || ry != j){
int tx = pre[rx][ry].first, ty = pre[rx][ry].second;
move(rx, ry, tx, ty);
rx = tx; ry = ty;
}
}
}
int main(){
freopen("changeful.in","r",stdin);
freopen("changeful.out","w",stdout);
n = read();
for(int i = 1; i <= n; ++i){
scanf("%s",s);
mp[s[1] - '0'][s[0] - 'a' + 1] = true;
}
if(n <= 32){
for(int i = 1; i <= 8; ++i)
for(int j = 1; j <= 8; ++j)
trans(i, j);
printf("%d\n",(int)ans.size());
for(pair<pii, pii> v : ans)printf("%c%d-%c%d\n",v.first.second + 'a' - 1, v.first.first, v.second.second + 'a' - 1, v.second.first);
}else{
for(int i = 1; i <= 8; ++i)
for(int j = 1; j <= 8; ++j)
mp[i][j] ^= 1;
for(int i = 8; i >= 1; --i)
for(int j = 8; j >= 1; --j)
trans(i, j);
printf("%d\n",(int)ans.size());
for(pair<pii, pii> v : ans)printf("%c%d-%c%d\n",v.second.second + 'a' - 1, v.second.first, v.first.second + 'a' - 1, v.first.first);
}
return 0;
}
C. 活罪难赦
性质的分析
二进制按位考虑
区间修改转查分
。。。
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 3e5 + 55, lg = 20;
int n, q, sum[lg][maxn], a[maxn]; char s[maxn];
int main(){
freopen("sins.in","r",stdin);
freopen("sins.out","w",stdout);
scanf("%d%s%d",&n, s, &q);
for(int i = 1; i < n; ++i)a[i] = s[i] ^ s[i - 1];
for(int i = 0; (1 << i) <= n; ++i){
int len = 1 << (i + 1);
for(int j = 1; j < len; ++j)sum[i][j] = a[j];
for(int j = len; j <= n; ++j)sum[i][j] = sum[i][j - len] + a[j];
}
for(int i = 1; i <= q; ++i){
int l = read(), r = read();
int ans = 0;
for(int j = 0; (1 << j) < (r - l + 1); ++j){
int cnt = (r - l + 1) >> (j + 1);
int c1 = sum[j][r - (1 << j) + 1];
if(l >= (1 << j))c1 -= sum[j][l - (1 << j)];
ans += min(c1, cnt - c1);
}
printf("%d\n",(ans + 1) >> 1);
}
}