我想要听你说说 此刻心中所想 有序杂乱 是谁在撒着谎 是谁撒开了网 书写者将造访 此处将被打造成停泊港

test11

厚牛堡(cow)

特判没有 \(0\) 的情况,然后对 \(1\) 的段考虑,考虑长度为 \(l\) 的段包含什么信息。

  • 不包含 \(str_1,str_n\),则时间 \(\leq \lfloor\frac{l-1}{2}\rfloor\)
  • 包含 \(str_1(str_n)\),则时间 \(\leq l\)

贪心希望时间最小,去还原每一段最多有多少奶牛即可。

#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 pb push_back 

using namespace std;

const int N=300005;

int n, len, Ans;
char str[N];

signed main() {
	freopen("cow.in","r",stdin);
	freopen("cow.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> (str+1);
	for(int l=1, r=1; l<=n; l=r+1, r=l) {
		if(str[l]=='0') continue;
		while(str[r+1]=='1') ++r;
		int val=r-l+1;
		if(val%2==0) --val;
		if(l==1) val=2*r-1;
		if(r==n) val=2*(n-l+1)-1;
		if(!len||val<len) len=val;
	}
	if(!len) { cout << 0 << '\n'; return 0; }
	for(int l=1, r=1; l<=n; l=r+1, r=l) {
		if(str[l]=='0') continue;
		while(str[r+1]=='1') ++r;
		if(r-l+1<len) ++Ans;
		else Ans+=(r-l+1+len-1)/len;
	}
	cout << Ans << '\n';
	return 0;
}

旅行商(tour)

考虑一个 dp 方程 \(f_u=\min\{f_u,max(f_v-p_{u\to v},w_{u\to v})\}\),为了更新我们期望获得一个美好的顺序。首先进 \(w\) 最大的边一定合法,然后没有贡献,不妨删掉,发现变成递归子问题,期间可以确定删空度数的点的贡献。

#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(register int i=l; i<=r; ++i)
#define dn(i,r,l) for(register int i=r; i>=l; --i) 
#define pb push_back

using namespace std;

const int N=200005, inf=2e9;

int n, m, f[N], in[N], out[N], vis[N];
struct node { int nxt, p, v, id; };
vector<node> F[N], G[N];
struct data{
	int i, j, p, v, id;
	bool operator<(const data &rhs) const { return v<rhs.v; }
} e[N];
queue<int> q;

signed main() {
    freopen("tour.in","r",stdin);
    freopen("tour.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m;
	up(i,1,m) {
		cin >> e[i].i >> e[i].j >> e[i].v >> e[i].p;
		e[i].id=i, ++in[e[i].j], ++out[e[i].i];
		F[e[i].i].pb((node){e[i].j,e[i].p,e[i].v,i});
		G[e[i].j].pb((node){e[i].i,e[i].p,e[i].v,i});
	}
	up(i,1,n) if(!out[i]) q.push(i);
	while(q.size()) {
		int x=q.front(); q.pop();
		for(node o:G[x]) if(!vis[o.id]) {
			int y=o.nxt;
			--in[x], --out[y], vis[o.id]=1;
			if(!out[y]) q.push(y);
		}
	}
	sort(e+1,e+1+m);
	up(i,1,n) f[i]=inf;
	dn(o,m,1) {
		if(vis[e[o].id]) continue;
		int i=e[o].i, j=e[o].j;
		vis[e[o].id]=1, --in[j], --out[i];
		f[i]=min(f[i],e[o].v);
		if(!out[i]) {
			q.push(i);
			while(q.size()) {
				int x=q.front(); q.pop();
				for(node o:G[x]) if(!vis[o.id]) {
					int y=o.nxt;
					--in[x], --out[y], vis[o.id]=1;
					f[y]=min(f[y],max(o.v,f[x]-o.p));
					if(!out[y]) q.push(y); 
				}
			} 
		}
	}
	up(i,1,n) {
		if(f[i]==inf) f[i]=-1;
		cout << f[i] << ' ';
	}
	return 0;
}

登山hike

因为操作不会让 \(h_j\) 变得比 \(h_i,h_k\) 小,所以结果是固定的,包含所有最大值的极小区间肯定都要改成最大值,然后左右边递归同理。然后考虑怎么操作是最优的,考虑值域是 \(\{sp_1,\dots,sp_m\}\),每次考虑把 \(h_i\leq sp_{u-1}\) 抬高成 \(sp_u\) 肯定是不劣的,因为反正 \(sp_{u-1}/sp_u\) 反正不能向未来贡献,那么现在不妨看看这个过程的最小贡献是什么。特判只用抬 \(0/1\) 个的情况,贪心的我们可以按照 最左最右中间、或最右最左中间的顺序依次操作,这样子中间的都可以获得最好的贡献,对于最左最右的组合也拿不到更好的贡献了。我们模拟这个过程,可以从大到小枚举 \(sp\),用线段树找 rmq,并查集快速找要操作最左最右的位置,我就不赘述了喵。

#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 ls(p) (p<<1)
#define rs(p) (p<<1|1)

using namespace std;

const int N=1000005, inf=1e18, P=1e6+3;

int n, h[N], sp[N], m, ran[N], Ans, tag[N];
int dl[N], dr[N], tr[N<<2];

int sum(int l,int r) {
	if((l+r)%2==0) return (l+r)/2*(r-l+1)%P;
	return (r-l+1)/2*(l+r)%P;
}
int getl(int x) { return x==dl[x]?x:dl[x]=getl(dl[x]); }
int getr(int x) { return x==dr[x]?x:dr[x]=getr(dr[x]); }
void merl(int i,int j) { i=getl(i), j=getl(j), dl[i]=dl[j]; }
void merr(int i,int j) { i=getr(i), j=getr(j), dr[i]=dr[j]; }

void modify(int x,int v,int p=1,int s=1,int e=n) {
	if(s==e) { tr[p]=v; return; }
	int mid=(s+e)>>1;
	if(x<=mid) modify(x,v,ls(p),s,mid);
	if(x>mid) modify(x,v,rs(p),mid+1,e);
	tr[p]=min(tr[ls(p)],tr[rs(p)]);
}

int query(int l,int r,int p=1,int s=1,int e=n) {
	if(l<=s&&e<=r) return tr[p];
	int mid=(s+e)>>1, L=inf, R=inf;
	if(l<=mid) L=query(l,r,ls(p),s,mid);
	if(r>mid) R=query(l,r,rs(p),mid+1,e);
	return min(L,R);
}

signed main() {
//	freopen("wa.in","r",stdin);
	freopen("hike.in","r",stdin);
	freopen("hike.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n;
	up(i,1,4*n) tr[i]=inf;
	up(i,1,n) cin >> h[i], sp[++m]=h[i], ran[i]=dl[i]=dr[i]=i;
	sort(sp+1,sp+1+m), m=unique(sp+1,sp+1+m)-sp-1;
	sort(ran+1,ran+1+n,[](int i,int j){return h[i]>h[j];});
	int c=0, L=0, R=0;
	dn(u,m,2) {
		int l=0, r=0;
		while(c<n&&h[ran[c+1]]>=sp[u]) {
			int i=ran[++c];
			if(!l||i<l) l=i;
			if(!r||i>r) r=i;
			tag[i]=1, modify(i,h[i]);
			if(tag[i-1]) merr(i-1,i), merl(i,i-1);
			if(tag[i+1]) merr(i,i+1), merl(i+1,i);
		}
		if(!L||l<L) L=l;
		if(!R||r>R) R=r;
		int ll=getr(L)+1, rr=getl(R)-1;
		if(R-L+1==c) continue;
		if(ll==rr) {
			int vl=query(L,ll-1), vr=query(ll+1,R);
			(Ans+=(sum(sp[u-1],sp[u]-1)+(vl+vr)%P*(sp[u]-sp[u-1])%P)%P)%=P;
		} 
		else {
			(Ans+=(R-L+1-c-2)*(sum(sp[u-1],sp[u]-1)+2*sum(sp[u-1]+1,sp[u])%P)%P)%=P;
			int a=query(L,ll-1), b=query(ll+1,R);
			int c=query(L,rr-1), d=query(rr+1,R);
			if(b<c) {
				(Ans+=((a+b)*(sp[u]-sp[u-1])%P+sum(sp[u-1],sp[u]-1))%P)%=P;
				(Ans+=((d*(sp[u]-sp[u-1])%P+sum(sp[u-1],sp[u]-1))%P+sum(sp[u-1]+1,sp[u]))%P)%=P;
			}
			else {
				(Ans+=((c+d)*(sp[u]-sp[u-1])%P+sum(sp[u-1],sp[u]-1))%P)%=P;
				(Ans+=((a*(sp[u]-sp[u-1])%P+sum(sp[u-1],sp[u]-1))%P+sum(sp[u-1]+1,sp[u]))%P)%=P;
			}
		}
	}
	cout << (Ans%P+P)%P << '\n';
	return 0; 
}
posted @ 2025-10-09 22:08  Hypoxia571  阅读(8)  评论(0)    收藏  举报