F
题意
- 有n个宝藏,每个宝藏有自己的val,你能获得前k个
- 同时,你还可以进行一些交换,每次交换消耗价值c
- 求解你可以获得的最大价值
思路
- 考虑将所有宝藏都换到最前面,取最高的k个,然后再加上把k个宝藏从第一个放到前k个的价值
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
signed main() {
cin.tie(0)->sync_with_stdio(0);
priority_queue<int> pq;
int n, k, c;
cin >> n >> k >> c;
vector<int> a(n);
for (auto &x : a) cin >> x;
for (int i = 0; i < n; i++) {
pq.emplace(a[i] - i * c);
}
int answer = 0;
for (int i = 0; i < k; i++) {
answer += pq.top();
pq.pop();
}
answer += k * (k - 1) / 2 * c;
cout << answer << endl;
return 0;
}
B
题意
- 一张n*m地图,判断有没有可能因为视野限制走入死胡同
思路
- 走入死胡同意味着,在k视野下看到是活路,但实际是死路,也就是思路的横向宽度大于等于k
- 从起点和终点分别跑一个dfs就能找到所有不可达的块,判断每一个块的宽度即可
代码
#include <bits/stdc++.h>
using namespace std;
void solve() {
int N, M, K;
cin >> N >> M >> K;
auto mp = vector(N + 2, string(M + 2, '1'));
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= M; j++) {
cin >> mp[i][j];
}
}
auto visit1 = vector(N + 2, vector(M + 2, false));
auto visit2 = vector(N + 2, vector(M + 2, false));
auto dot = vector(N + 2, vector(M + 2, false));
auto dfs1 = [&](auto &self, int x, int y) -> void {
if (mp[x][y] == '1') return;
if (visit1[x][y]) return;
visit1[x][y] = true;
self(self, x + 1, y);
self(self, x - 1, y);
self(self, x, y + 1);
};
dfs1(dfs1, 1, 1);
auto dfs2 = [&](auto &self, int x, int y) -> void {
if (mp[x][y] == '1') return;
if (visit2[x][y]) return;
visit2[x][y] = true;
self(self, x + 1, y);
self(self, x - 1, y);
self(self, x, y - 1);
};
dfs2(dfs2, 1, M);
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= M; j++) {
dot[i][j] = visit1[i][j] && !visit2[i][j];
}
}
auto visit = vector(N + 2, vector(M + 2, false));
auto search = [&](auto &self, int x, int y, int width) -> int {
visit[x][y] = true;
int a1 = 1, a2 = 1, a3 = 1;
if (!visit[x + 1][y] && dot[x + 1][y])
a1 = self(self, x + 1, y, width);
if (!visit[x - 1][y] && dot[x - 1][y])
a2 = self(self, x - 1, y, width);
if (!visit[x][y + 1] && dot[x][y + 1])
a3 = self(self, x, y + 1, width + 1);
return max({a1, a2, a3, width});
};
int maxwidth = 0;
for (int j = 1; j <= M; j++) {
for (int i = 1; i <= N; i++) {
if (dot[i][j] && !visit[i][j])
maxwidth = max(maxwidth, search(search, i, j, 1));
}
}
if (maxwidth < K)
cout << "No\n";
else
cout << "Yes\n";
}
int main() {
int T;
cin >> T;
while (T--) solve();
return 0;
}
G
题意
- 给一个合法括号序列s,每个字符有1/2的概率变成?,请问获得的含?序列可以唯一还原成合法序列的概率
思路
- 对于一个子序列,可被唯一合法还原的条件是:
- 必须是若干个'('在前,然后若干个')',因为只要存在")(",将这两个交换必然合法,存在多种方案
- 交换最后一个'('和第一个')'前缀和序列存在负值(非法情况)
- 枚举l表示最后一个被变成'?'的'('的位置,然后找r为第一个被变成'?'的')'的位置
代码
#include<bits/stdc++.h>
using namespace std;
using ll =long long ;
const int p=998244353;
ll qpow(ll a,ll b){
ll ans=1;
while(b){
if(b&1) ans=ans*a%p;
a=a*a%p;
b>>=1;
}
return ans;
}
ll ans=0;
ll a[1010101],pre[1010101],suf[1010101],sum[1010101];
int main(){
string s;
cin >> s;
s=' '+s;
for(int i=1;i<s.length();i++) {
a[i]=(s[i]=='('?1:-1);
sum[i]=a[i]+sum[i-1];
// cout << sum[i] << ' ' ;
}
// cout << endl;
for(int i=1;i<s.length();i++) pre[i]=pre[i-1]+(a[i]==1);
for(int i=s.length()-1;i>=1;i--) suf[i]=suf[i+1]+(a[i]==-1);
for(int l=1,r=1;l<s.length();l++){
while(r<s.length()&&(sum[r]>1||r<l)) r++;
if(r==s.length())break;
if(a[l]==1){
// cout << l << ' ' << r << ' ' << pre[l-1] << ' ' << suf[r+1] << endl;
ans=(ans+(qpow(2,pre[l-1])*qpow(2,suf[r+1])%p))%p;
// cout << ans << endl;
}
}
ans=(ans+qpow(2,(s.length()/2))%p);
// cout << ans << endl;
ll inv=qpow(qpow(2,s.length()-1),p-2);
cout << (ans*inv)%p << endl;
return 0;
}
I
题意
- n*m的推箱子地图,箱子自己移动,判断是否存在不超过1e5长度的解
思路
- 对于每个箱子跑bfs,找到最近的目标,然后恢复路径,从终点往箱子回溯,如果路上遇到箱子,就清空路径
- 形式化的:对于箱子A和终点C,回溯A->C的路径中遇到箱子B则存储两段路径,B->C,A->B
代码
#include<bits/stdc++.h>
#define pii pair<int,int>
#define f first
#define s second
using namespace std;
/**
* 每个箱子广搜
* 途中遇到未到位的箱子怎么办?
* 途中遇到已经到位的箱子怎么办?
* 每个箱子搜出来一条路,回溯这个路,回溯的过程中,如果遇到已经占位的别的箱子,就分成两段
* Eg.A->C中间,B处有一个箱子,所得路径C->a
* 从C回溯,到B遇见障碍,将C->B记为一段
* 然后从B继续回溯,直到A
* 这样就获得了B->C,A->B的两段路径
*/
int n,m;
int dir[4][2]={0,1,0,-1,1,0,-1,0};
string mp[55];
vector<pair<pii,pii>> path;
int vis[55][55];
int prex[55][55];
int prey[55][55];
vector<pair<pair<int,int>,char>> ans;
char getdir(pii now,pii lst){
if(now.f==lst.f){
return lst.s>now.s?'L':'R';
}else{
return lst.f>now.f?'U':'D';
}
}
void creat(){
// for(auto [x,y]:path){
// cout << x.f+1 << ' ' << x.s+1 << "->" << y.f+1 << ' ' << y.s+1 << endl;
// }
int flg=-1;
for(int i=0;i<path.size();i++){
pii now1=path[i].f,lst1=path[i].s;
if(mp[lst1.f][lst1.s]!='.'){
for(int j=i;j>flg;j--){
pii now2=path[j].f,lst2=path[j].s;
ans.push_back({{lst2.f,lst2.s},getdir(now2,lst2)});
}
// cout<< "OK"<< i<<' '<< flg <<endl;
flg=i;
}
}
mp[path.back().s.f][path.back().s.s]='.';
mp[path[0].f.f][path[0].f.s]='!';
}
bool check(pii tp){
if(tp.f<0||tp.f>=n||tp.s<0||tp.s>=m||mp[tp.f][tp.s]=='#'||vis[tp.f][tp.s]) return false;
return true;
}
void bfs(int x,int y){
queue<pii> q;
memset(vis,0,sizeof(vis));
memset(prex,0,sizeof(prex));
memset(prey,0,sizeof(prey));
path.clear();
q.push({x,y});
vis[x][y]=1;
prex[x][y]=-1;
prey[x][y]=-1;
while(!q.empty()){
pii now=q.front();
q.pop();
if(mp[now.f][now.s]=='*'){
while(prex[now.f][now.s]!=-1||prey[now.f][now.s]!=-1){
pii lst={prex[now.f][now.s],prey[now.f][now.s]};
path.push_back({now,lst});
now=lst;
}
return ;
}
for(int i=0;i<4;i++){
pii next={now.f+dir[i][0],now.s+dir[i][1]};
if(check(next)){
q.push(next);
vis[next.f][next.s]=1;
prex[next.f][next.s]=now.f;
prey[next.f][next.s]=now.s;
}
}
}
}
int main(){
cin >> n >> m;
for(int i=0;i<n;i++){
cin >> mp[i];
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(mp[i][j]=='@'){
bfs(i,j);
if(path.size()==0){
cout << -1 << endl;
return 0;
}
creat();
}
}
}
cout << ans.size() << endl;
for(auto [x,y]:ans){
cout << x.f+1 << ' ' << x.s+1 << ' ' << y << endl;
}
return 0;
}