8.1测试

A.Doughnut

因为数据范围为\(10^6\),且结合题意,我们可以考虑用dp的方法来解决。
设计状态为:\(f_i\)//表示第一次到i点时需要的步数
因为想要前进一步就必须保证当前这一格的甜甜圈是偶数个,所以每次到一个新的点\(i\)上后都需要返回\(p_i\)点,从\(p_i\)点重新走到\(i\)点。
所以,到达一个新的点\(i\)所需要的步数是第一次到前i-1个点的步数+1+返回\(p_i\)点后重新到达i-1点的步数;
可设计转移方程为:\(f_{i+1}=f_{i}+1+f_{i}-f_{p_i}+1\)
时间复杂度为:\(O(n)\)

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=1e6+5;
const int mod=1e9+7;

ll n;
ll a[N],f[N];

int main()
{
	n=read();
	for(int i=1;i<=n;i++)a[i]=read();
	f[1]=0;
	for(int i=1;i<=n;i++)
	{
		f[i+1]=f[i]+1+(f[i]-f[a[i]])+1;
		f[i+1]%=mod;
	}
	cout<<(f[n+1]+mod)%mod<<endl;
	return 0;
 } 

B.Pudding

线段树存储数据,f数组记录在区间\([l,r]\)中子序列\((0w0)\)的数量。
\(f[p][i][j]\)来表示在编号为\(p\)的子树中子序列\((,(0,(0w,(0w0,0),w0),0w0),(0w0)\)的个数;
转移方程为:\(f[p][i][j]=f[p*2][i][j]+f[p*2+1][i][j]+\sum_{i\leq k <j}{f[p*2][i][k]*f[p*2+1][k+1][j]}\)

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

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 ll mod=4294967296;
const int N=5e4+5;

int n,m,tg[N*4];
struct ww{
	int l,r,len;
}tr[N*4];
int f[N*4][5][5];

char s[N];

void updat(int p)
{
	for(int i=0;i<=4;i++)
	{
		for(int j=i;j<=4;j++)
		{
			f[p][i][j]=f[p<<1][i][j]+f[p<<1|1][i][j];
			for(int k=i;k<j;k++)
			f[p][i][j]+=f[p<<1][i][k]*f[p<<1|1][k+1][j];
		}
	}
}

void build(int p,int l,int r)
{
	tr[p].l=l,tr[p].r=r;
	tr[p].len = r-l+1;
	if(r==l)
	{
		if(s[l]=='(')f[p][0][0]=1;
		else if(s[l]=='0')f[p][1][1]=f[p][3][3]=1;
		else if(s[l]=='w')f[p][2][2]=1;
		else if(s[l]==')')f[p][4][4]=1;
		return ;
	}
	int mid=(l+r)>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
	updat(p);
}

void downdat(int p)
{
	if(tg[p]==0)return ;
	if(tr[p].len>1)
	{
		tg[p<<1]=tg[p<<1|1]=tg[p];
	}
	memset(f[p],0,sizeof(f[p]));
	if(tg[p]==(int)'(')f[p][0][0]=tr[p].len;
	else if(tg[p]==(int)'0')
	f[p][1][1]=f[p][3][3]=tr[p].len;
	else if(tg[p]==(int)'w')
	f[p][2][2]=tr[p].len;
	else if(tg[p]==(int)')')
	f[p][4][4]=tr[p].len;
	tg[p]=0;
}

void change(int p,int l_,int r_,int c)
{
	int l=tr[p].l,r=tr[p].r;
	if(l>r_||r<l_)return ;
	if(l>=l_&&r<=r_)
	{
		tg[p]=c;
		downdat(p);
		return ;
	}
	downdat(p<<1),downdat(p<<1|1);
	int mid=(l+r)>>1;
	if(l_<=mid)change(p<<1,l_,r_,c);
	if(r_>mid)change(p<<1|1,l_,r_,c);
	updat(p);
}

int ans[5][5],tmp[5][5];

void uion(int x[5][5],int y[5][5],int z[5][5])
{
	for(int i=0;i<=4;i++)
	{
		for(int j=i;j<=4;j++)
		{
			x[i][j]=y[i][j]+z[i][j];
			for(int k=i;k<j;k++)
			x[i][j]+=y[i][k]*z[k+1][j];
		}
	}
}

void ask(int p,int l_,int r_)
{
	int l=tr[p].l,r=tr[p].r;
	if(r_<l||r<l_)return ;
	if(l_<=l&&r<=r_)
	{
//		cout<<l<<" "<<r<<endl;
		uion(ans,tmp,f[p]);
		for(int i=0;i<=4;i++)
		{
			for(int j=i;j<=4;j++)
			tmp[i][j]=ans[i][j]; 
		}
//		cout<<ans[0][4]<<endl;
		return ;
	}
	downdat(p<<1);downdat(p<<1|1);
	int mid=(l+r)>>1;
	if(l_<=mid)ask(p<<1,l_,r_);
	if(r_>mid)ask(p<<1|1,l_,r_);
}

int main()
{
	n=read(),m=read();
	for(int i=1;i<=n;i++)cin>>s[i];
	build(1,1,n);
	char opt,z;int x,y; 
	for(int i=1;i<=m;i++)
	{
		cin>>opt;
		if(opt=='A')
		{
			x=read();cin>>z;
			change(1,x,x,(int)z);
		}
		else if(opt=='B')
		{
			x=read(),y=read();
			cin>>z;
			change(1,x,y,(int)z);
		}
		else
		{
			x=read(),y=read();
			memset(ans,0,sizeof ans);
			memset(tmp,0,sizeof tmp);
			ask(1,x,y);
			ll tmp1=ans[0][4];
			printf("%lld\n",(tmp1%mod+mod)%mod);
		}
	} 
	return 0;
}

C.Tiramisu

AC Code
posted @ 2022-08-01 21:08  两只风小鱼  阅读(33)  评论(0)    收藏  举报