191030-模拟测试10
T1 序列
题目描述
解析
首先问题转换为寻找一个最大的区间[l,r][l,r][l,r]使得suma[r]>suma[l−1],sumb[r]>sumb[l−1]suma[r]>suma[l-1],sumb[r]>sumb[l-1]suma[r]>suma[l−1],sumb[r]>sumb[l−1](suma[i],sumb[i]suma[i],sumb[i]suma[i],sumb[i]为前缀和数组),那么我们只需要用树状数组维护即可
题解
#include<bits/stdc++.h>
#define int long long
#define INF 1e8
using namespace std;
struct node
{
int b,aa,bb,w;
}s[1000009];
int n,a[1000009],ans,tree[1000009],len;
bool comp(const node &x,const node &y)
{
if(x.aa!=y.aa) return x.aa<y.aa;
if(x.bb!=y.bb) return x.bb<y.bb;
return x.w<y.w;
}
int lowbit(int i)
{
return i&(-i);
}
void minn(int x,int val)
{
while(x<=len)
{
tree[x]=min(tree[x],val);
x+=lowbit(x);
}
}
int query(int x)
{
int sum=INF;
while(x>0)
{
sum=min(sum,tree[x]);
x-=lowbit(x);
}
return sum;
}
signed main()
{
int x;
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&x);
s[i].aa=s[i-1].aa+x;
}
for(int i=1;i<=n;i++)
{
scanf("%lld",&x);
s[i].w=i;
s[i].bb=s[i-1].bb+x;
a[i]=s[i].bb;
}
sort(a+1,a+n+1);
len=unique(a+1,a+n+1)-a-1;
for(int i=1;i<=n;i++)
s[i].b=lower_bound(a+1,a+len+1,s[i].bb)-a;
sort(s+1,s+n+1,comp);
memset(tree,127,sizeof(tree));
for(int i=1;i<=n;i++)
{
ans=max(ans,s[i].w-query(s[i].b));
minn(s[i].b,s[i].w);
if(s[i].aa>=0&&s[i].bb>=0)
ans=max(ans,s[i].w);
}
printf("%lld",ans);
return 0;
}
T2 二叉搜索树
题目描述
解析
f[i][j]f[i][j]f[i][j]表示将i−ji-ji−j中的所有节点建成一颗二叉搜索树,所需要付出的代价的最小值,因此可以用区间dp解决该题,f[i][j]=min(f[i][k−1]+f[k+1][j]+x[i..j])f[i][j]=min{(f[i][k-1]+f[k+1][j]}+x[i..j])f[i][j]=min(f[i][k−1]+f[k+1][j]+x[i..j])表示我们当前要以k为根节点,合并i...k−1,k+1...ji...k-1,k+1...ji...k−1,k+1...j的节点为一棵二叉搜索树,因为合并后,每个节点会向下一层,因此我们要多付出的代价为xi+...+xjx_i+...+x_jxi+...+xj,可以用前缀和来维护,即sumj−sumi−1sum_j-sum_{i-1}sumj−sumi−1;
但这样的时间复杂度为O(n3)O(n^3)O(n3),因此我们要考虑优化。
因为不会斜率优化dp ,因此考虑四边形不等式优化dp,然而我不会证明该题对于四边形不等式成立,因此可以通过打表来寻找规律,最后发现它具有决策单调性,因此时间复杂度优化至O(n2)O(n^2)O(n2)
题解
#include<bits/stdc++.h>
#define INF 1e18
using namespace std;
long long f[5011][5011],sum[5100],n;
int g[5011][5011],v;
inline long long read()
{
long long f=1,re=0;
char ch;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-')
{
f=-1;
ch=getchar();
}
for(;(ch>='0'&&ch<='9');ch=getchar())
re=(re<<3)+(re<<1)+ch-'0';
return re*f;
}
signed main()
{
long long x;
n=read();
for(int i=1;i<=n;i++)
{
x=read();
sum[i]=sum[i-1]+x;
f[i][i]=x;
g[i][i]=i;
}
for(int i=1;i<n;i++)
for(int j=1;(v=j+i)<=n;j++)
{
f[j][v]=INF;
for(int k=g[j][v-1];k<=g[j+1][v];k++)
if(f[j][v]>f[j][k-1]+f[k+1][v])
{
f[j][v]=f[j][k-1]+f[k+1][v];
g[j][v]=k;
}
f[j][v]+=(sum[v]-sum[j-1]);
}
printf("%lld",f[1][n]);
return 0;
}
附上暴力代码
#include<bits/stdc++.h>
#define int long long
#define INF 1e18
using namespace std;
int f[5010][5011],sum[5100],n;
int read()
{
int f=1,re=0;
char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-')
{
f=-1;
ch=getchar();
}
for(;isdigit(ch);ch=getchar())
re=(re<<3)+(re<<1)+ch-'0';
return re*f;
}
signed main()
{
int x;
n=read();
for(int i=1;i<=n;i++)
{
x=read();
sum[i]=sum[i-1]+x;
f[i][i]=x;
}
for(int i=1;i<n;i++)
for(int j=1;(j+i)<=n;j++)
{
f[j][i+j]=INF;
for(int k=j;k<=(i+j);k++)
f[j][i+j]=min(f[j][i+j],f[j][k-1]+f[k+1][i+j]);
f[j][i+j]+=(sum[i+j]-sum[j-1]);
}
printf("%lld",f[1][n]);
return 0;
}
T3 走路
题目描述
解析
话说这道题,我是真不会, 不过该题还是有可以让我这个菜鸡学习的地方,首先问题要求的是期望,因此我们需要知道求期望的方法,看下面一张图:
f[i]表示从起点(可以是选择的任意一点)到i点所走的期望边数
因此f[k]可以先跨过一条边,有13\frac{1}{3}31的概率走到u,v,w点来得到f[u],f[v],f[w]f[u],f[v],f[w]f[u],f[v],f[w]的期望值,因此f[k]=13∗(f[u]+f[v]+f[w])+1f[k]=\frac{1}{3}*(f[u]+f[v]+f[w])+1f[k]=31∗(f[u]+f[v]+f[w])+1,其他点也可以类比,最后解一个多元一次方程即可。
题解
//#include<bits/stdc++.h>
#include<iostream>
#define L long long
#define vi vector<int>
#define pb push_back
using namespace std;
const int q=998244353;
int n,m,f[310][310],g[10][310][310],x[310][310];
bool y[310][310];
inline int power(int a,int b)
{
if(!b)
return 1;
int c=power(a,b>>1);
c=(L)c*c%q;
if(b&1)
c=(L)c*a%q;
return c;
}
inline void dfs(int l,int i)
{
int j;
x[l][i]=f[i][0];
for(j=1;j<=n;j++)
if(j!=i && f[i][j])
{
if(!y[l][j])
dfs(l,j);
x[l][i]=(x[l][i]-(L)f[i][j]*x[l][j])%q;
}
y[l][i]=1;
}
inline void calc(int l,int r,int p)
{
int i,j,k,m=(l+r)>>1;
if(l==r)
{
y[l][l]=1;
for(i=1;i<=n;i++)
if(!y[l][i])
dfs(l,i);
return;
}
for(i=l;i<=r;i++)
{
g[p][i][0]=f[i][0];
for(j=l;j<=r;j++)
g[p][i][j]=f[i][j];
}
for(i=l;i<=m;i++)
{
k=power(f[i][i],q-2);
f[i][0]=(L)f[i][0]*k%q;
for(j=i;j<=r;j++)
f[i][j]=(L)f[i][j]*k%q;
for(j=i+1;j<=r;j++)
if(f[j][i])
{
f[j][0]=(f[j][0]-(L)f[i][0]*f[j][i])%q;
for(k=r;k>=i;k--)
f[j][k]=(f[j][k]-(L)f[i][k]*f[j][i])%q;
}
}
calc(m+1,r,p+1);
for(i=l;i<=r;i++)
{
f[i][0]=g[p][i][0];
for(j=l;j<=r;j++)
f[i][j]=g[p][i][j];
}
for(i=r;i>m;i--)
{
k=power(f[i][i],q-2);
f[i][0]=(L)f[i][0]*k%q;
for(j=l;j<=i;j++)
f[i][j]=(L)f[i][j]*k%q;
for(j=i-1;j>=l;j--)
if(f[j][i])
{
f[j][0]=(f[j][0]-(L)f[i][0]*f[j][i])%q;
for(k=l;k<=i;k++)
f[j][k]=(f[j][k]-(L)f[i][k]*f[j][i])%q;
}
}
calc(l,m,p+1);
for(i=l;i<=r;i++)
{
f[i][0]=g[p][i][0];
for(j=l;j<=r;j++)
f[i][j]=g[p][i][j];
}
}
int main()
{
//freopen("walk.in","r",stdin);
//freopen("walk.out","w",stdout);
int i,j,k;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
{
scanf("%d%d",&j,&k);
f[j][j]++;
f[j][0]++;
f[j][k]--;
}
calc(1,n,0);
for(i=2;i<=n;i++)
printf("%d\n",(x[i][1]+q)%q);
return 0;
}