2022/8/18 总结

A.P2587 [ZJOI2008]泡泡堂

  • 好家伙,久违的贪心所以说挂了

Solution

  • 古人的智慧;

  • 但实际上这道题和田忌赛马有所区别,已知有一种比较优的方法是用己方最鶸的换掉敌方最强的,那么为了得分最大,就有如下策略:

    • 当己方最强比敌方最强强时,得 \(2\) 分;
    • 否则,如果己方最弱比敌方最弱强,得 \(2\) 分;
    • 否则,用己方最弱换掉敌方最强。如果刚好平局,按平局计算这就是极限一换一吗
AC code
#include<bits/stdc++.h>
using namespace std;

inline int read(){
	int s=0,f=1;
	char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		s=s*10+int(ch-'0');
		ch=getchar();
	}
	return s*f;
}

const int N=1e5+10;

int n;
int a[N],b[N];

int count(int x[],int y[]){
	int ans=0;
	int lx=1,ly=1,rx=n,ry=n;
	while(lx<=rx && ly<=ry){
		if(x[lx]>y[ly]){
			ans+=2;
			++lx,++ly;
		}
		else if(x[rx]>y[ry]){
			ans+=2;
			--rx,--ry;
		}
		else{
			ans+=(x[lx]==y[ry]);
			++lx;
			--ry;
		}
	}
	return ans;
}

int main(){
//	freopen("bubble.in","r",stdin);
//	freopen("bubble.out","w",stdout);
	n=read();
	for(int i=1;i<=n;++i)
		a[i]=read();
	for(int i=1;i<=n;++i)
		b[i]=read();
	sort(a+1,a+n+1);
	sort(b+1,b+n+1);
	printf("%d %d",count(a,b),(n<<1)-count(b,a));
	return 0;
}

B.P4492 [HAOI2018]苹果树

  • 考场上被直接跳过并再也没有回来的题;

Solution

  • 万万没有想到,这题居然是排列组合

  • 分析加入点数与方案数的关系,容易发现其实是 \(n!\),再考虑每条边的贡献和每个子树的生成方案数,总之最后一通乘积转化之后会发现答案就是:

    \[\sum_{i=1}^n \sum_{j=1}^{n-i+1}\times j\times(n-j)\times j!\times\dbinom{n-i}{j-1}\times i!\times\frac{(n-j-1)!}{(i-2)!} \]

  • 再化简之后:

    \[\sum_{i=1}^n \sum_{j=1}^{n-i+1}\times j\times (n-j)\times j!\times\dbinom{n-i}{j-1}\times(n-j-1)!\times i\times(i-1) \]

AC code
#include<bits/stdc++.h>
using namespace std;

#define int long long

const int N=2e3+10;

int n,mod;
int f[N][N],c[N][N],mul[N];

signed main(){
	scanf("%lld%lld",&n,&mod);
	for(int i=0;i<=n;++i)
		c[i][i]=c[0][i]=1;
	for(int i=0;i<=n;++i)
		for(int j=1;j<=n;++j)
			(c[j][i]=0ll+c[j-1][i-1]+c[j][i-1])%=mod;
	mul[0]=1;
	for(int i=1;i<=n;++i)
		(mul[i]=1ll*mul[i-1]*i)%=mod;
	f[1][1]=1;
	for(int i=2;i<=n;++i)
		for(int j=1;j<=i;++j)
			(f[i][j]=1ll*mul[i-2]*j%mod*(j-1))%=mod;
	int ans=0;
	for(int i=2;i<=n;++i)
		for(int j=1;j<=n-i+1;++j)
			(ans+=1ll*mul[j]*c[j-1][n-i]%mod*j*(n-j)%mod*f[n-j+1][i])%=mod;
	printf("%lld",ans);
	return 0;
}

C.P3736 [HAOI2016]字符合并

  • 暴力都挂了……

Solution

  • 状压&区间 \(\mathtt{DP}\)。把 \(01\) 串全部压成二进制。

  • \(f_{i,j,t}\) 表示将区间 \([i,j]\) 压缩后状态为 \(t\) 的最大得分。按照区间 \(\mathtt{DP}\) 一般形式来枚举断点 \(p\),但还要套一层枚举状态的循环。

  • 状态转移方程为:

    • \(f_{i,j,t<<1}=\max(f_{i,j,t<<1},f_{i,p-1,t}+f_{p,j,0})\)
    • \(f_{i,j,t<<1|1}=\max(f_{i,j,p<<1|1},f_{i,p-1,t}+f_{p,j,1})\)
  • 最后统计合并了 \([1,n]\) 的所有可能状态中得分最大的即可。

AC code
#include<bits/stdc++.h>
using namespace std;

inline int read(){
	int s=0,f=1;
	char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-') f=-1;
		ch=getchar();
	} 
	while(isdigit(ch)){
		s=s*10+int(ch-'0');
		ch=getchar();
	}
	return s*f;
}

const int N=305;
const int Inf=0x3f3f3f3f;

#define ll long long

int n,k;
int a[N];
int c[N],v[N];
ll f[N][N][N];

int main(){
	n=read(),k=read();
	for(int i=1;i<=n;++i)
		a[i]=read();
	for(int i=0;i<(1<<k);++i)
		c[i]=read(),v[i]=read();
	memset(f,-Inf,sizeof(f));
	for(int i=n;i;--i){
		for(int j=i;j<=n;++j){
			if(i==j){
				f[i][j][a[i]]=0;
				continue;
			}
			int len=(j-i)%(k-1);
			if(!len) len=k-1;
			for(int p=j;p>i;p-=k-1){
				for(int q=0;q<(1<<len);++q){
					f[i][j][q<<1]=max(f[i][j][q<<1],f[i][p-1][q]+f[p][j][0]);
					f[i][j][q<<1|1]=max(f[i][j][q<<1|1],f[i][p-1][q]+f[p][j][1]);
				}
			}
			if(len!=k-1) continue;
			ll cnt[2]={-Inf,-Inf};
			for(int p=0;p<(1<<k);++p)
				cnt[c[p]]=max(cnt[c[p]],f[i][j][p]+v[p]);
			f[i][j][0]=cnt[0],f[i][j][1]=cnt[1];
//			cout<<i<<" "<<j<<" "<<f[i][j][0]<<" "<<f[i][j][1]<<endl;
		}
	}
	ll ans=-Inf;
	for(int i=0;i<(1<<k);++i)
		ans=max(ans,f[1][n][i]);
	printf("%lld",ans);
	return 0;
}

D.P4344 [SHOI2015]脑洞治疗仪

  • 为什么这人的脑洞越治越大,这真的不是脑洞制造仪吗

  • 线段树,但考试时不知道为什么挂了;

Solution

  • 线段树,具体存储方法类比用线段树求一个序列答案;
AC code
#include<bits/stdc++.h>
using namespace std;

inline int read(){
	int s=0,f=1;
	char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		s=s*10+int(ch-'0');
		ch=getchar();
	}
	return s*f;
}

const int N=2e5+10;
const int Inf=0x3f3f3f3f;

int n,m;

struct memr{
	int l,r,siz;
	int sum,tg;
	int mx,lmx,rmx;
}tr[N<<4];

void pushup(int p){
	tr[p].sum=tr[p<<1].sum+tr[p<<1|1].sum;
	tr[p].mx=max(tr[p<<1].mx,tr[p<<1|1].mx);
	tr[p].mx=max(tr[p].mx,tr[p<<1].rmx+tr[p<<1|1].lmx);
	tr[p].lmx=tr[p<<1].lmx;
	tr[p].rmx=tr[p<<1|1].rmx;
	if(tr[p<<1].mx==tr[p<<1].siz)
		tr[p].lmx=max(tr[p].lmx,tr[p<<1].siz+tr[p<<1|1].lmx);
	if(tr[p<<1|1].mx==tr[p<<1|1].siz)
		tr[p].rmx=max(tr[p].rmx,tr[p<<1|1].siz+tr[p<<1].rmx);
	return ;
}

void push(int p,int tg){
	if(tg==1){
		tr[p].sum=tr[p].siz;
		tr[p].lmx=tr[p].mx=tr[p].rmx=0;
	}
	else if(tg==-1){
		tr[p].sum=0;
		tr[p].lmx=tr[p].mx=tr[p].rmx=tr[p].siz;
	}
	return ;
}

void pushdown(int p){
	if(tr[p].tg){
		push(p<<1,tr[p].tg);
		push(p<<1|1,tr[p].tg);
		tr[p<<1].tg=tr[p].tg;
		tr[p<<1|1].tg=tr[p].tg;
		tr[p].tg=0;
	}
	return ;
}

void build(int p,int l,int r){
	tr[p].l=l,tr[p].r=r;
	tr[p].siz=r-l+1;
	tr[p].tg=0;
	tr[p].lmx=tr[p].mx=tr[p].rmx=0;
	if(l==r){
		tr[p].sum=1;
		return ;
	}
	int mid=(l+r)>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
	pushup(p);
	return ;
}

void change(int p,int l,int r,int v){
	if(l<=tr[p].l && tr[p].r<=r){
		push(p,v);
		tr[p].tg=v;
		return ;
	}
	pushdown(p);
	int mid=(tr[p].l+tr[p].r)>>1;
	if(l<=mid) change(p<<1,l,r,v);
	if(mid<r) change(p<<1|1,l,r,v);
	pushup(p);
	return ;
}

memr ask_hole(int p,int l,int r){
	if(l<=tr[p].l && tr[p].r<=r)
		return tr[p];
	pushdown(p);
	int mid=(tr[p].l+tr[p].r)>>1;
	memr L,R,cnt;
	bool sl=0,sr=0;
	if(l<=mid)
		L=ask_hole(p<<1,l,r),sl=1;
	if(mid<r)
		R=ask_hole(p<<1|1,l,r),sr=1;
	pushup(p);
	if(sl && !sr)
		return L;
	if(!sl && sr)
		return R;
	if(sl && sr){
		cnt.sum=L.sum+R.sum;
		cnt.siz=L.siz+R.siz;
		cnt.mx=max(L.rmx+R.lmx,max(L.mx,R.mx));
		cnt.lmx=L.lmx,cnt.rmx=R.rmx;
		if(L.mx==L.siz)
			cnt.lmx=max(cnt.lmx,L.mx+R.lmx);
		if(R.mx==R.siz)
			cnt.rmx=max(cnt.rmx,R.mx+L.rmx);
	}
	return cnt;
}

int ask_num(int p,int l,int r){
	if(l<=tr[p].l && tr[p].r<=r)
		return tr[p].sum;
	pushdown(p);
	int cnt=0;
	int mid=(tr[p].l+tr[p].r)>>1;
	if(l<=mid) cnt+=ask_num(p<<1,l,r);
	if(mid<r) cnt+=ask_num(p<<1|1,l,r);
	pushup(p);
	return cnt;
}

int Fill(int p,int l,int r,int x){
	if(!x) return 0;
	if(l<=tr[p].l && tr[p].r<=r && tr[p].siz-tr[p].sum<=x){
		int s=tr[p].siz-tr[p].sum;
		push(p,1);
		tr[p].tg=1;
		return x-s;
	}
	pushdown(p);
	int cnt;
	if(tr[p<<1].r<l) cnt=Fill(p<<1|1,l,r,x);
	else if(tr[p<<1|1].l>r) cnt=Fill(p<<1,l,r,x);
	else cnt=Fill(p<<1|1,l,r,Fill(p<<1,l,r,x));
	pushup(p);
	return cnt;
}

int main(){
//	freopen("head.in","r",stdin);
//	freopen("head.out","w",stdout);
	n=read(),m=read();
	build(1,1,n+1);
	int opt,l,r,x,y;
	while(m--){
		opt=read(),l=read(),r=read();
		if(opt==1){
			x=read(),y=read();
			int len=ask_num(1,l,r);
			if(!len) continue;
			change(1,l,r,-1);
			Fill(1,l,r,len);
		}
		else{
			if(opt==0)
				change(1,l,r,-1);
			else{
				memr ans=ask_hole(1,l,r);
				printf("%d\n",ans.mx);
			}
		}
	}
	return 0;
}
posted @ 2022-08-18 18:59  Star_LIcsAy  阅读(28)  评论(0)    收藏  举报