8.20总结

Blue Mary的战役地图

\(solution\)
暴力卡常
时间复杂度较高\(O(n^7)\)
优化后可过:

倒叙枚举边长,一旦找到就输出

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=55;
int n;
int a[N][N],b[N][N];

bool dfs(int x,int y,int k)
{
	for(int i=1;i<=n-k+1;i++)
	{
		for(int j=1;j<=n-k+1;j++)
		{
			if(b[i][j]==a[x][y])
			{
				int o=0;
				for(int s=0;s<k;s++)
				{
					for(int w=0;w<k;w++)
					{
						if(a[x+s][y+w]!=b[i+s][j+w])
						{
							o=1;
							break;
						}
					}
					if(o==1)break;
				}
				if(o==0)return true;
			}
		}
	}
	return false;
}

int main()
{
//	freopen("map.in","r",stdin);
//	freopen("map.out","w",stdout);
	n=read();
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			a[i][j]=read();
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			b[i][j]=read();
	int ans=0;
	for(int k=n;k>=1;k--)
	{
		for(int i=1;i<=n-k+1;i++)
		{
			for(int j=1;j<=n-k+1;j++)
			{
				if(dfs(i,j,k))
				{
					ans=k;
					printf("%d\n",ans);
					return 0;
				}
			}
		}
	}
	return 0;
}

无界单词

\(solution\)
对于总的无界单词的个数,我们考虑用dp来解决。

设计状态\(f_i\)表示长度为i的无界单词个数,由此可得转移方程为:\(f_i=2^{i}-\sum_{j=1}^{i/2}{f_{j}*2^{i-2*j}}\)

然后我们来考虑第k小的无界单词

kmp预处理+dp找在已经确定了len长的串后的无界单词个数

转移方程为:\(f_{i}=2^{i-len}-\sum_{j=1}^{i/2}{a_j}\)

分类讨论:

  1. \(len\leq j,a_j=f_{j}*2^{i-j*2}\)
  2. 否则\(len\leq i-j,a_j=f_j*2^{i-len-j}\)
  3. 否则,判断\(w_{1\cdots len-i+j}\)\(w_{1\cdots len}\)是否相等,如果不相等\(w_j=1,k-=f[n]\)

通过帮助zcy,我知道了位移64位等于位移0位,所以一定要有数组预处理2的i次幂

AC Code
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
inline ull read()
{
	ull 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;
}

ull t,n,k,qow[100];
ull nex[100],w[100],f[100];

void kmp(int len)
{
	for(int i=2,j=0;i<=len;i++)
	{
		while(j>0&&w[j+1]!=w[i])j=nex[j];
		if(w[j+1]==w[i])j++;
		nex[i]=j;
	}
}

ull init(int len)
{
	memset(f,0,sizeof f);
	for(int i=1;i<=n;i++)
	{
		if(i<=len)
		{
			f[i]=!nex[i];
			continue;
		}
		f[i]=qow[i-len];
		for(int j=1;j<=i/2;j++)
		{
			if(j>=len)f[i]-=f[j]*qow[i-j*2];
			else if(len<=i-j)f[i]-=f[j]*qow[i-len-j];
			else if(f[j])
			{
				int o=0;
				for(int s=1,p=i-j+1;p<=len;++p,++s)
				{
					if(w[s]!=w[p])
					{
						o=1;break;
					}
				}
				if(!o)f[i]--;
			}
		}
	}
	return f[n];
}

int main()
{
//	freopen("word.in","r",stdin);
//	freopen("word.out","w",stdout);
	t=read();
	qow[0]=1;
	for(int i=1;i<=64;i++)
	qow[i]=qow[i-1]*2;
	while(t--)
	{
		n=read(),k=read();
		memset(f,0,sizeof f);
		for(int i=1;i<=n;i++)
		{
			f[i]=qow[i];
			for(int j=1;j<=i/2;j++)
			f[i]-=f[j]*qow[i-2*j];
		}
		cout<<f[n]<<endl;
		for(int i=1;i<=n;i++)
		{
			w[i]=0;kmp(i);
			ull tmp=init(i);
			if(tmp<k)w[i]=1,k-=tmp;
		}
		for(int i=1;i<=n;i++)
		{
			if(w[i]==1)printf("b");
			else printf("a");
		}
		printf("\n");
	}
	return 0;
}

病毒感染

\(solution\)

Blue Mary开公司

\(solution\)
我们考虑用李超线段树来做这道题

建一棵[1,5e4]的线段树,对于一个区间上的节点,记录使这个区间收益最大的经营方案

每次有一个新的经营方案,就加入线段树中,如果这个区间的原方案完全高于新的方案,不做更改,如果原方案完全低于新的方案,就覆盖掉原方案。如果没有完全低于或完全高于,则下传。

查询时,因为没有上传,所以ans需比较所有包含x的区间的方案的值。

如果不写change,线段树会WA

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

const int N=2e6+5;
const int M=5e4;
int n;
char opt[10];
struct ww{
	int l,r;
	double a,b;
}tr[N];

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

void change(int p,int l,int r,double a,double b)
{
	int l1=tr[p].l,r1=tr[p].r;
	if(l<=l1&&r1<=r)
	{
		double yl=(l1-1)*tr[p].a+tr[p].b;
		double yr=(r1-1)*tr[p].a+tr[p].b;
		double yl_=(l1-1)*a+b;
		double yr_=(r1-1)*a+b;
		if(yl<=yl_&&yr<=yr_)
		{
			tr[p].a=a,tr[p].b=b;
			return ;
		}
		if(yl>=yl_&&yr>=yr_)
			return ;
	}
	int mid=(l1+r1)>>1;
	if(l<=mid)change(p<<1,l,r,a,b);
	if(r>mid)change(p<<1|1,l,r,a,b);
}

double ask(int p,int x,double ans)
{
	ans=max(ans,(x-1)*tr[p].a+tr[p].b);
	if(tr[p].l==tr[p].r&&tr[p].l==x)
		return ans;
	int mid=(tr[p].l+tr[p].r)>>1;
	if(x<=mid)return ask(p<<1,x,ans);
	return ask(p<<1|1,x,ans);
}

int main()
{
//	freopen("company.in","r",stdin);
//	freopen("company.out","w",stdout);
	scanf("%d",&n);
	build(1,1,M);
	double a,b;int x;
	while(n--)
	{
		scanf("%s",opt);
		if(opt[0]=='P')
		{
			cin>>b>>a;
			change(1,1,M,a,b);
		}
		else
		{
			scanf("%d",&x);
			printf("%d\n",(int)(ask(1,x,0)/100.0));
		}
	}
	return  0;
}
posted @ 2022-08-20 14:57  两只风小鱼  阅读(29)  评论(0)    收藏  举报