空白 脑里 琐碎 堆砌 一点点 一滴滴 渐渐填满缝隙

test16

一个困难的问题difficult

首先区间排序是假的,因为可以冒泡排序,这样子可能好考虑一点。

不难发现可以倒序考虑,要贡献的选择后缀中最小未选择的即可,构造的话可以直接从后往前考虑每次最小值的位置一定在上一个贡献位置的前面,那么直接排序拉到要贡献的位置即可。

#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

using namespace std;

const int N=100005;

int T, n, a[N], Ans, tag[N];
char b[N];

void mian() {
	cin >> n, Ans=0;
	up(i,1,n) cin >> a[i];
	cin >> (b+1);
	
	priority_queue<int> qwq;
	dn(i,n,1) {
		qwq.push(-a[i]);
		if(b[i]=='1') {
			Ans-=qwq.top();
			qwq.pop();
		}
	}
	cout << Ans << '\n';
}

signed main() {
//	freopen("1.txt","r",stdin);
	freopen("difficult.in","r",stdin);
	freopen("difficult.out","w",stdout); 
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> T;
	while(T--) mian();
	return 0;
}

数字游戏number

\(f(n,m)\) 表示还有 \(n\) 轮游戏,钦定 \(m\) 个加法的和是多少,对于第一个人 \((n,m)\) 有唯一常数 \(t\),对于第二个人有 \(f(n,m)=\min\{f(n-1,m)-p,f(n,m-1)+p\}\),那么显然 \(p=\frac{f(n-1,m-1)+f(n-1,m)}{2}\)。首先 \(\frac{1}{2}\) 的贡献只跟 \(n\) 相关先不考虑,剩下的部分是一个类杨辉三角,画出来做差分直到好看之后组合意义求解即可。

#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)

using namespace std;

const int N=3000005, P=1e9+7;

int T, n, m, k, mul[N], inv[N];

int C(int n,int m) {
	if(m<0||n<m) return 0;
	return mul[n]*inv[m]%P*inv[n-m]%P;
}

signed main() {
//	freopen("1.txt","r",stdin);
	freopen("number.in","r",stdin);
	freopen("number.out","w",stdout); 
	ios::sync_with_stdio(0);
	cin.tie(0);
	mul[0]=inv[0]=inv[1]=1;
	up(i,1,3e6) mul[i]=mul[i-1]*i%P;
	up(i,2,3e6) inv[i]=inv[P%i]*(P-P/i)%P;
	up(i,2,3e6) inv[i]=inv[i-1]*inv[i]%P;
	cin >> T;
	while(T--) {
		cin >> n >> m >> k;
		int Ans=0;
		up(i,1,m) (Ans+=C(n,m-i)*i%P)%=P;
		up(i,2,n) (Ans*=inv[2])%=P;
		cout << Ans*k%P << '\n';
	}
	return 0;
}

子序列seq

矩阵乘法优化 dp,线段树维护修改即可。

#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=200005, M=9;

int n, len, q;
char str[N], s[M]={0,'a','b','c','c','d','b'};
struct mat {
	int n, m, d[M][M];
	void insert(int u,char v) {
		n=m=8;
		memset(d,0,sizeof(d));
		if(v==s[1]) ++d[7][1]; else ++d[7][6];
		if(v==s[6]) d[5][8]=len-u+1; //cout << "v = " << n << ' ' << u << ' ' << n-u+1 << '\n';
		up(i,1,5) if(v==s[i+1]) ++d[i][i+1]; else ++d[i][i];
		if(v==s[1]) ++d[6][1]; else ++d[6][6];
		++d[7][7], ++d[8][8];
	}
	void clear(int nn,int mm) {
		n=nn, m=mm;
		memset(d,0,sizeof(d));
	}
} tr[N<<2], qwq;

mat mul(mat a,mat b) {
	mat c; c.clear(a.n,b.m);
	up(i,1,a.n) up(j,1,b.m) up(k,1,a.m) {
		c.d[i][j]+=a.d[i][k]*b.d[k][j];
	}
	return c;
}

void build(int p=1,int s=1,int e=n) {
	if(s==e) {
		tr[p].insert(s,str[s]);
		return;
	}
	int mid=(s+e)>>1;
	build(ls(p),s,mid), build(rs(p),mid+1,e);
	tr[p]=mul(tr[ls(p)],tr[rs(p)]);
} 

void updata(int x,int p=1,int s=1,int e=n) {
	if(s==e) {
		tr[p].insert(s,str[s]);
		return;
	}
	int mid=(s+e)>>1;
	if(x<=mid) updata(x,ls(p),s,mid);
	if(x>mid) updata(x,rs(p),mid+1,e);
	tr[p]=mul(tr[ls(p)],tr[rs(p)]);
}

int ans() {
	mat res=mul(qwq,tr[1]);
	return res.d[1][8]; // 修改 
}

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

signed main() {
	freopen("seq.in","r",stdin);
	freopen("seq.out","w",stdout); 
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> (str+1), n=len=strlen(str+1);
	build(); 
	qwq.n=1, qwq.m=8, qwq.d[1][7]=1;
	mat res=qwq;
//	up(i,0,n) {
//		cout << "Round " << i << " : "; 
//		if(i) res=mul(res,get(i));
//		up(j,1,8) cout << res.d[1][j] << ' '; cout << '\n';
//	} return 0;
	cout << ans() << '\n';
	cin >> q;
	while(q--) {
		int x; char v;
		cin >> x >> v;
		str[x]=v, updata(x);
		cout << ans() << '\n';
	}
	return 0;
}

新生life

感觉对询问找 \(c\) 是很复杂并且很大的东西,不妨对于每一个 \(c\) 找到护甲的最小值。

暴力怎么做?总伤害显然是 \(c\sum a_ib_i\),考虑最多能消掉多少伤害,那么显然是顺次考虑每一个时间、选择 \(b\) 最大的消除一个。类似于廊桥分配,从大到小考虑某个值依次贪心即可,换言之 \(\geq x\) 的子结构一定包含在 \(\geq x-1\) 的子结构里面,现在 \(O(n)\) 枚举 \(\geq x\) 问题变成了求最大匹配,考虑 hall 定理 \(c(\sum a_i)-\max\{|S|-|N(S)|\}\),发现 \(N(S)\) 是一个好枚举的后缀 \(t_i+1,\dots,T\),想要最大化 \(|S|\) 就取一个前缀,所以按照 \(t_i\downarrow\),考虑前缀和 \(s_i\)\(c\) 的最大匹配就是直线最大值,然后求答案还要乘一个 \(x_i-x_{i+1}(x_{n+1}=0)\),斜率优化之后系数打到数组上做前缀和即可快速计算,询问显然是二分或者双指针就行了。

#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
#define k first
#define b second

using namespace std;

inline int read() {
    int X=0; bool flag=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') flag=0; ch=getchar(); }
    while(ch>='0'&&ch<='9') { X=(X<<1)+(X<<3)+ch-'0'; ch=getchar(); }
    if(flag) return X;
    return ~(X-1);
}

const int N=6005, M=10000005, Q=1000005;

int id, n, m, C, T, q, sp[N], len, sav, stk[N], top, s1[M], s2[M], ran;
int fc[M], tot;
pii l[N], qur[Q]; 
struct node { int t, a, b; } arr[N], con[N];

int beat(pii x,pii y) {
	int l=y.b-x.b, r=x.k-y.k;
	return (l%r==0)?(l/r):(l/r+1); 
}

inline void add(int l,int r,int k,int b) { s1[l]+=k, s1[r+1]-=k, s2[l]+=b, s2[r+1]-=b; }

signed main() {
	n=read(), C=read(), T=read();
	up(i,1,n) {
		arr[i].t=read(), arr[i].a=read(), arr[i].b=read();
		sp[++m]=arr[i].b, ran+=arr[i].a*arr[i].b;
	}
	sort(arr+1,arr+1+n,[](node i,node j){return i.t>j.t;});
	sort(sp+1,sp+1+m), m=unique(sp+1,sp+1+m)-sp-1, sp[m+1]=0;
	up(i,1,m/2) swap(sp[i],sp[m-i+1]);
	up(u,1,m) {
		len=tot=sav=0;
		up(i,1,n) if(arr[i].b>=sp[u]) con[++len]=arr[i];
		l[1]=mp(0,0);
		up(i,1,len) {
			con[i].a+=con[i-1].a;
			l[i+1]=mp(con[i].a,-(T-con[i].t));
		}
		tot=con[len++].a;
//		sort(l+1,l+1+len);
		up(i,1,len) {
			if(i==1||l[i].k!=l[sav].k) l[++sav]=l[i];
			else l[sav].b=max(l[sav].b,l[i].b);
		} len=sav;
		stk[top=1]=1;
		up(i,2,len) {
			while(top>1&&beat(l[i],l[stk[top]])<=beat(l[stk[top]],l[stk[top-1]])) --top;
			stk[++top]=i;
		}
		int lst=C+1;
		while(top>1&&beat(l[stk[top]],l[stk[top-1]])>=lst) --top;
		while(top) {
			int qwq=(top==1)?0:beat(l[stk[top]],l[stk[top-1]]);
			add(qwq,lst-1,(tot-l[stk[top]].k)*(sp[u]-sp[u+1]),(-l[stk[top]].b)*(sp[u]-sp[u+1]));
			lst=qwq, --top;
		}
	}
	up(i,1,C) s1[i]+=s1[i-1], s2[i]+=s2[i-1], fc[i]=ran*i-s1[i]*i-s2[i];
	q=read();
	up(i,1,q) {
		qur[i].first=i;
		qur[i].second=read();
	}
	sort(qur+1,qur+1+q,[](pii i,pii j){return i.second<j.second;});
	int j=0;
	up(i,1,q) {
		while(j+1<=C&&fc[j+1]<=qur[i].second) ++j;
		qur[i].second=j;
	}
	sort(qur+1,qur+1+q,[](pii i,pii j){return i.first<j.first;});
	up(i,1,q) printf("%lld\n", qur[i].second);
	return 0;
}
posted @ 2025-10-11 20:21  Hypoxia571  阅读(7)  评论(0)    收藏  举报