无限欢愉 深入咽喉 请别祈求 我的宽厚 请别妄想 还能忍受 在结局来临之后

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;
}
posted @ 2025-11-10 22:08  Hypoxia571  阅读(11)  评论(0)    收藏  举报