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

浙公网安备 33010602011771号