8.18总结

泡泡堂

solution
这道题有点像田忌赛马,但不全是。
贪心策略:

如果我方最强强于对方最强,ans+=2;
如果我方最弱强于对方最弱,ans+=2;
否则最弱打最强送死为其他人创造机会

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

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=x*10+ch-'0';
		ch=getchar();
	}
	return x*f;
}

const int N=1e5+5;
int n,a[N],b[N];

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);
	int ans=0,l1=1,r1=1;
	int l2=n,r2=n;
	while(l1<=l2&&r1<=r2)
	{
		if(a[l1]>b[r1]){
			ans+=2;l1++,r1++;
		}
		else if(a[l2]>b[r2])
		{
			ans+=2;l2--,r2--;
		}
		else if(a[l1]==b[r2])
		{
			ans++;
			l1++;r2--;
		}
		else l1++,r2--;
	}
	printf("%d ",ans);
	ans=0,l1=r1=1;
	l2=r2=n;
	while(l1<=l2&&r1<=r2)
	{
		if(b[l1]>a[r1]){
			ans+=2;l1++,r1++;
		}
		else if(b[l2]>a[r2])
		{
			ans+=2;l2--,r2--;
		}
		else if(b[l1]==a[r2])
		{
			ans++;
			l1++;r2--;
		}
		else l1++,r2--;
	}
	printf("%d\n",n*2-ans);
	return 0;
}

苹果树

solution
真就有了结论后很快做出来,可惜考试时推不出结论

根据大佬的推论,我们可以得到一个式子:
image

把这个式子简化一下可以得到:
image

预处理一下组合数就可以很快求出答案

AC Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline ll read()
{
	ll x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=x*10+ch-'0';
		ch=getchar();
	}
	return x*f;
}

const int N=2005;
ll n,p,ans,m[N],c[N][N];

int main()
{
	n=read(),p=read();
	m[0]=1;
	for(int i=1;i<=n;i++)
	m[i]=m[i-1]*i%p;
	for(int i=0;i<=n;i++)c[i][0]=1;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=i;j++)
		{
			c[i][j]=(c[i-1][j-1]+c[i-1][j])%p;
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n-i+1;j++)
		{
			ans+=j*(n-j)%p*m[j]%p*c[n-i][j-1]%p*m[n-j-1]%p*i%p*(i-1)%p;
			ans%=p;
		}
	}
	cout<<ans<<endl;
	return 0;
}

字符合并

solution

因为合并的区间之间互不干扰,且n300,所以我们考虑区间dp。因为k8,所以我们考虑状压dp。所以这道题是区间dp+状压dp。

设计状态:fl,r,s表示把区间[l,r]合并成状态s的最大价值

因为对于一个长为len的序列,我们最终一定会把它合并成一个长为(len1)的序列,所以状态s不超过(1<<k)1

枚举中间节点t,我们可以得到状态转移方程为:

fl,r,s2=max(fl,t1,s+ft,r,0)

fl,r,s2+1=max(fl,t1,s+ft,r,1)

(len1)时,长为len的序列可以合并为一个字符,需要单独枚举最大价值

p=0(1<<k)1(c[p]==0)?tmp1=max(fl,r,p+wp):tmp2=max(fl,r,p+wp)

fl,r,0=tmp1,fl,r,1=tmp2

AC Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline ll read()
{
	ll x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=x*10+ch-'0';
		ch=getchar();
	}
	return x*f;
}

const int N=305;
const ll inf=0x3f3f3f3f3f3f3f3f;
ll n,k,c[N],w[N];
ll f[N][N][N];
char a[N];

int main()
{
	n=read(),k=read();
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=0;i<(1<<k);i++)
	{
		c[i]=read(),w[i]=read();
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			for(int p=0;p<(1<<k);p++)
			f[i][j][p]=-inf;
		}
	}
	for(int i=1;i<=n;i++)f[i][i][a[i]-'0']=0;
	for(int len=2;len<=n;len++)
	{
		for(int l=1;l<=n-len+1;l++)
		{
			int r=l+len-1;
			int len_=(len-1)%(k-1);
			if(len_==0)len_=k-1;
			for(int s=r;s>l;s-=k-1)
			{
				for(int p=0;p<(1<<len_);p++)
				{
					f[l][r][p*2]=max(f[l][r][p*2],f[s][r][0]+f[l][s-1][p]);
					f[l][r][p*2+1]=max(f[l][r][p*2+1],f[s][r][1]+f[l][s-1][p]);
				}
			}
			if(len_==k-1)
			{
				ll tmp1=-inf,tmp2=-inf;
				for(int p=0;p<(1<<k);p++)
				{
					if(f[l][r][p]!=-inf)
					{
						if(c[p]==1)
						{
							tmp2=max(tmp2,f[l][r][p]+w[p]);
						}
						else
						{
							tmp1=max(tmp1,f[l][r][p]+w[p]);
						}
					}
				}
				f[l][r][0]=tmp1,f[l][r][1]=tmp2;
			}
		}
	}
	ll ans=-inf;
	for(int i=0;i<(1<<k);i++)
	{
		ans=max(ans,f[1][n][i]);
	}
	cout<<ans<<endl;
	return 0;
}

脑洞治疗仪

solution
万万没想到,我50pts的原因是数组没开够
线段树维护修改操作,注意先挖后补

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

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=x*10+ch-'0';
		ch=getchar();
	}
	return x*f;
}

const int N=2e5+5;
int n,m;

struct ww{
	int l,r,sum,lm,rm,len;
	int dat,tag;
}tr[N*8];

void updat(int p)
{
	tr[p].sum=max(max(tr[p<<1].sum,tr[p<<1|1].sum),tr[p<<1].rm+tr[p<<1|1].lm);
	tr[p].dat=tr[p<<1].dat+tr[p<<1|1].dat;
	if(tr[p<<1].sum==tr[p<<1].len)
	{
		tr[p].lm=tr[p<<1].len+tr[p<<1|1].lm;
	}
	else tr[p].lm=tr[p<<1].lm;
	if(tr[p<<1|1].sum==tr[p<<1|1].len)
	{
		tr[p].rm=tr[p<<1|1].len+tr[p<<1].rm;
	}
	else tr[p].rm=tr[p<<1|1].rm;
}

void build(int p,int l,int r)
{
	tr[p].l=l,tr[p].r=r;
	tr[p].len=r-l+1;
	if(l==r)return ;
	int mid=(l+r)>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
	updat(p);
}

void pushdown(int p)
{
	if(tr[p].tag==1)
	{
		tr[p<<1].tag=1;
		tr[p<<1].sum=tr[p<<1].lm=tr[p<<1].rm=tr[p<<1].dat=tr[p<<1].len;
		tr[p<<1|1].tag=1;
		tr[p<<1|1].sum=tr[p<<1|1].lm=tr[p<<1|1].rm=tr[p<<1|1].dat=tr[p<<1|1].len;
		tr[p].tag=0;
	}
	if(tr[p].tag==2)
	{
		tr[p<<1].tag=2;
		tr[p<<1].sum=tr[p<<1].lm=tr[p<<1].rm=tr[p<<1].dat=0;
		tr[p<<1|1].tag=2;
		tr[p<<1|1].sum=tr[p<<1|1].lm=tr[p<<1|1].rm=tr[p<<1|1].dat=0;
		tr[p].tag=0;
	}
}

void change1(int p,int l,int r)
{
	int l1=tr[p].l,r1=tr[p].r;
	if(r1<l||r<l1)return ;
	if(l<=l1&&r1<=r)
	{
		pushdown(p);
		tr[p].tag=1;
		tr[p].sum=tr[p].lm=tr[p].rm=tr[p].dat=tr[p].len;
		return ;
	}
	pushdown(p);
	int mid=(l1+r1)>>1;
	if(l<=mid)change1(p<<1,l,r);
	if(r>mid)change1(p<<1|1,l,r);
	updat(p);
}

ww ask1(int p,int l,int r)
{
	int l1=tr[p].l,r1=tr[p].r;
	if(l<=l1&&r1<=r)
	{
		pushdown(p);
		return tr[p];
	}
	pushdown(p);
	ww ans,tr1,tr2;
	int o1=0,o2=0;
	int mid=(l1+r1)>>1;
	if(l<=mid)
	{
		tr1=ask1(p<<1,l,r);
		o1=1;
	}
	if(r>mid)
	{
		tr2=ask1(p<<1|1,l,r);
		o2=1;
	}
	updat(p);
	if(o1==0)return tr2;
	if(o2==0)return tr1;
	ans.sum=max(max(tr1.sum,tr2.sum),tr1.rm+tr2.lm);
	ans.len=tr1.len+tr2.len;
	if(tr1.sum==tr1.len)
	{
		ans.lm=tr1.len+tr2.lm;
	}
	else ans.lm=tr1.lm;
	if(tr2.sum==tr2.len)
	{
		ans.rm=tr2.len+tr1.rm;
	}
	else ans.rm=tr2.rm;
	return ans;
}

int ask2(int p,int l,int r)
{
	int l1=tr[p].l,r1=tr[p].r;
	if(r1<l||r<l1)return 0;
	if(l<=l1&&r1<=r)
	{
		pushdown(p);
		return tr[p].dat;
	}
	pushdown(p);
	int ans=0;
	int mid=(l1+r1)>>1;
	if(l<=mid)ans+=ask2(p<<1,l,r);
	if(r>mid)ans+=ask2(p<<1|1,l,r);
	updat(p);
	return ans;
}

int dat1;

void change2(int p,int l,int r)
{
	int l1=tr[p].l,r1=tr[p].r;
	if(r1<l||r<l1)return ;
	if(dat1==0)return ;
	if(l<=l1&&r1<=r&&tr[p].dat<=dat1)
	{
		dat1-=tr[p].dat;
		pushdown(p);
		tr[p].tag=2;
		tr[p].sum=tr[p].dat=tr[p].lm=tr[p].rm=0;
		return ;
	}
	pushdown(p);
	int mid=(l1+r1)>>1;
	if(l<=mid)change2(p<<1,l,r);
	if(r>mid)change2(p<<1|1,l,r);
	updat(p);
}

int main()
{
//	freopen("head.in","r",stdin);
//	freopen("head.out","w",stdout);
	n=read(),m=read();
	int opt,l,r;
	build(1,1,n);
	for(int i=1;i<=m;i++)
	{
		opt=read(),l=read(),r=read();
		if(opt==0)
		{
			change1(1,l,r);
		}
		else if(opt==1)
		{
			int l1,r1;
			l1=read(),r1=read();
			dat1=r-l+1-ask2(1,l,r);
			change1(1,l,r);
			change2(1,l1,r1);
		}
		else
		{
			int tmp=ask1(1,l,r).sum;
			printf("%d\n",tmp);
		}
	}
	return 0;
}
posted @   两只风小鱼  阅读(18)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起