无限欢愉 深入咽喉 请别祈求 我的宽厚 请别妄想 还能忍受 在结局来临之后
test36
8-A 字符替换 (replace.cpp)
好像不是很好全局分析,又这个是 t1,不妨想想怎么直接贪心再考虑正确性。
从左到右做,如果碰到一个 \(\text{B}\to \text{A}\),那么希望向右找到一个最左边的 \(\text{A}\to \text{B}\),如果找不到那就随便找右边的一个 \(\text{A}\to \text{A}\),不能找 \(\to \text{A}\) 因为可以证明就是不行。如果碰到一个 \(\text{A}\to \text{B}\),因为好的贡献已经被弄完了,所以找左边的一个 \(\to \text{A}\),同理不能找 \(\to \text{B}\) 因为可以证明反正就是不行。
#pragma GCC optimize(1,2,3,"Ofast","inline")
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
using namespace std;
const int N=200005;
int n, Ans, a[N], b[N], p[N], top, tag[N];
char s[N], t[N];
signed main() {
freopen("replace.in","r",stdin);
freopen("replace.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> (s+1) >> (t+1);
up(i,1,n) if(s[i]=='A'&&t[i]=='B') p[++top]=i;
up(i,1,n) a[i]=a[i-1]+(t[i]=='A');
dn(i,n,1) b[i]=b[i+1]+(t[i]=='B');
int i=1;
up(u,1,n) {
if(tag[u]) continue;
if(s[u]=='B'&&t[u]=='A') {
while(i<=top&&p[i]<u) ++i;
++Ans;
if(i<=top) tag[p[i++]]=1;
else if(!b[u+1]) { cout << -1 << '\n'; return 0; }
}
if(s[u]=='A'&&t[u]=='B') {
++Ans;
if(!a[u-1]) { cout << -1 << '\n'; return 0; }
}
}
cout << Ans << '\n';
return 0;
}
8-B 采矿 (mining.cpp)
难点在于这道题不是背包。
考虑体积取值为 \(v_1<\dots<v_m\),因为题目的特殊性质我们就,\(\times \frac{1}{v_i}\) 意义下考虑体积 \(m(\times \frac{1}{v_i})\mod{\frac{v_{i+1}}{v_i}}\) 的答案,这个时候所有物品体积一样,显然贪心尽量选取最大的不劣,然后考虑处理剩下的贡献,按照价值排序多个合并成一个即可。
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
using namespace std;
const int N=500005, M=42;
int n, m, Ans, sp[N], tot;
vector<int> w[M], l[N];
struct node { int v, w; } p[N];
signed main() {
freopen("mining.in","r",stdin);
freopen("mining.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
up(i,1,n) {
cin >> p[i].w >> p[i].v;
sp[++tot]=p[i].v;
}
sort(sp+1,sp+1+tot), tot=unique(sp+1,sp+1+tot)-sp-1;
sort(p+1,p+1+n,[](node i,node j){return i.w>j.w;});
up(i,1,n) {
up(j,1,tot) if(sp[j]==p[i].v) {
w[j].pb(p[i].w);
break;
}
}
vector<int> mer;
up(u,1,tot) {
int res=m/sp[u];
if(u<tot) res%=(sp[u+1]/sp[u]);
vector<int> ran;
int i=0, j=0;
while(i<mer.size()&&j<w[u].size()) {
if(mer[i]>w[u][j]) ran.pb(mer[i++]);
else ran.pb(w[u][j++]);
}
while(i<mer.size()) ran.pb(mer[i++]);
while(j<w[u].size()) ran.pb(w[u][j++]);
mer.clear(), w[u].clear();
int sav=0, cnt=0;
for(int i:ran) {
if(res>0) --res, Ans+=i;
else {
++cnt, sav+=i;
if(u<tot&&cnt==sp[u+1]/sp[u]) mer.pb(sav), cnt=sav=0;
}
}
if(sav) mer.pb(sav);
}
cout << Ans << '\n';
return 0;
}
8-C 沙滩旅客 (beach.cpp)
对于一个间隔,贡献是一个考虑剖开第 \(u\) 层,则有长度为 \(\frac{len}{2^u}\) 的 \(2^u\) 个毯子,所以 \(u\leq \log k\),想法是可以直接计算出所有的毯子种类然后排序。现在问题在于查找 \((l,r,u)\) 的具体第 \(1\leq i\leq 2^u\) 条毯子具体在类线段树的形态上的位置编号,通俗的说就是关心有多少个 \(<u\) 的点也占了间隔,考虑画出这个线段树的形态,可以先对 \(1\to i-1\) 这段树剖出大块的贡献,最后再计算 \(root\to i\) 链上的贡献。发现这样子做超空间,我们考虑离线,用优先队列顺着扫下去来代替直接排序,这样子顺便还能稍微优化一点点复杂度,改变 $\log $ 的对象。
#pragma GCC optimize(1,2,3,"Ofast","inline")
#include<bits/stdc++.h>
#define ll long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
using namespace std;
const int N=1000005, inf=1e9;
int n, lim, T, sum, a[N];
pii p[N];
struct frac {
ll x, y;
frac() {}
frac(ll X,ll Y=1) {
ll d=__gcd(X,Y);
x=X/d, y=Y/d;
}
} Ans[N];
frac operator*(frac i,int j) { return frac(i.x*j,i.y); }
frac operator/(frac i,int j) { return frac(i.x,i.y*j); }
frac operator+(frac i,frac j) { return frac(i.x*j.y+j.x*i.y,i.y*j.y); }
bool operator<(frac i,frac j) { return i.x*j.y<j.x*i.y; }
bool operator==(frac i,frac j) { return i.x==j.x&&i.y==j.y; }
struct node {
int l, u;
frac d;
node() {}
node(int L,int U,frac D) { l=L, u=U, d=D; }
bool operator<(const node &rhs) const { return d==rhs.d?l>rhs.l:d<rhs.d; }
}; priority_queue<node> q;
signed main() {
freopen("beach.in","r",stdin);
freopen("beach.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> lim >> T;
up(i,1,n) cin >> a[i];
up(i,1,T) cin >> p[i].first, p[i].second=i;
up(i,2,n) q.push(node(a[i-1],0,frac(a[i]-a[i-1],2)));
sort(p+1,p+1+T);
node now=q.top(); q.pop();
q.push(node(now.l,now.u+1,now.d/2));
up(i,1,T) {
int x=p[i].first, sav=p[i].first;
while(sum+(1<<now.u)<x) {
sum+=(1<<now.u);
now=q.top(), q.pop();
q.push(node(now.l,now.u+1,now.d/2));
}
dn(u,30,0) if((sav-1-sum)>>u&1) x+=(1<<u)-1;
for(int u=sav-sum; u>1; u=(u+1)/2) if(u%2==0) ++x;
Ans[p[i].second]=frac(now.l)+now.d*(x-sum);
}
up(i,1,T) cout << Ans[i].x << '/' << Ans[i].y << '\n';
return 0;
}
8-D 地下城与勇士 (dungeon.cpp)
先思考策略是什么,用当前走过的+看到的点确定可能的 \(S\),然后考虑有没有对于这些 \(S\) 都安全的新路可以走,有的话就扩宽我的视野。
好像直接模拟就可以过了,但是可能要求写法跑不满、常数相对正常。划分开一些 \(S\) 的点集,先尽可能拓展,然后划开。
#pragma GCC optimize(1,2,3,"Ofast","inline")
#include<bits/stdc++.h>
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define opt first
#define val second
using namespace std;
const int N=65, M=405, inf=1e9;
const int dx[8]={1,-1,0,0,1,1,-1,-1}, dy[8]={0,0,1,-1,1,-1,1,-1};
int n, m, len, x[N], y[N], Ans=inf;
vector<int> tag[N];
char str[M][M];
inline int id(int p,int q) { return p*(m+2)+q+1; }
inline char real(int i,pii u) {
int xx=x[i]+u.first, yy=y[i]+u.second;
if(xx<0||xx>n+1||yy<0||yy>m+1) return 'E';
return str[xx][yy];
}
inline char see(int i,pii u) {
char res=real(i,u);
return res=='X'?'.':res;
}
void Sort(int st,int ed) {
queue<pii> q;
up(i,1,n) up(j,1,m) if(!tag[st][id(i,j)]) {
bool chk=0;
up(o,0,3) if(tag[st][id(i+dx[o],j+dy[o])]) chk=1;
if(chk) q.push(mp(i-x[st],j-y[st]));
}
while(q.size()) {
pii u=q.front(); q.pop();
if(tag[st][id(x[st]+u.first,y[st]+u.second)]) continue;
bool flag=1;
char pre=real(st,u);
if(pre!='o'&&pre!='.') continue;
up(i,st+1,ed) {
if(real(i,u)!=pre) {
flag=0;
break;
}
}
if(flag) {
up(i,st,ed) tag[i][id(x[i]+u.first,y[i]+u.second)]=1;
up(o,0,3) {
int X=u.first+dx[o]+x[st], Y=u.second+dy[o]+y[st];
if(X<1||X>n||Y<1||Y>m) continue;
q.push(mp(u.first+dx[o],u.second+dy[o]));
}
}
}
vector<pii> diff;
up(i,0,n+1) up(j,0,m+1) if(!tag[st][id(i,j)]) {
bool chk=0;
up(o,0,8) {
int X=i+dx[o], Y=j+dy[o];
if(X<0||X>n+1||Y<0||Y>m+1) continue;
if(tag[st][id(i+dx[o],j+dy[o])]) chk=1;
}
if(chk) diff.pb(mp(i-x[st],j-y[st]));
}
for(int l=st, r=l; l<=ed; l=r+1, r=l) {
up(i,l+1,ed) {
bool flag=1;
for(pii u:diff) {
if(see(l,u)!=see(i,u)) {
flag=0;
break;
}
}
if(flag) {
swap(tag[++r],tag[i]);
swap(x[r],x[i]);
swap(y[r],y[i]);
}
}
if(l>st||r<ed) Sort(l,r);
else {
int res=0;
up(i,1,n) up(j,1,m) if(tag[l][id(i,j)]) res+=(str[i][j]=='o');
Ans=min(Ans,res);
}
}
}
signed main() {
freopen("dungeon.in","r",stdin);
freopen("dungeon.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
up(i,1,n) cin >> (str[i]+1);
up(i,0,n+1) str[i][0]=str[i][m+1]='*';
up(i,0,m+1) str[0][i]=str[n+1][i]='*';
up(i,1,n) up(j,1,m) if(str[i][j]=='S') {
str[i][j]='.', ++len, x[len]=i, y[len]=j;
tag[len].resize((n+2)*(m+2)+1), tag[len][id(i,j)]=1;
}
Sort(1,len);
cout << Ans << '\n';
return 0;
}

浙公网安备 33010602011771号