[CSP-S模拟测试76]题解

咕咕咕

A.序列

无解情况:$n>a*b$或$n<a+b-1$

把序列分成B段,每段内部上升,各段分界处构成下降子序列。

实现并不是太简单,要动态地考虑一下边界什么的。

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int T,n,a,b;
void work()
{
    scanf("%d%d%d",&n,&a,&b);
    if(n>1LL*a*b||n<a+b-1)
    {
        puts("No");
        return ;
    }
    puts("Yes");
    int beg=n-a+1;
    for(int i=beg;i<=n;i++)
        printf("%d ",i);
    if(b==1)return ;
    b--;
    int bl=(beg-1)/b,now=beg-bl;
    while(b)
    {
        bl=(beg-1)/b;
        now=beg-bl;
        for(int i=now;i<beg;i++)
            printf("%d ",i);
        beg=now;
        b--;
    }
    putchar('\n');
}

int main()
{
    scanf("%d",&T);
    while(T--)work();
    return 0;
}

B.购物

按套路来讲,答案区间应该是连续的?

并不是。如果把$a[]$排序后求前缀和,会发现如果$\frac{a_i}{2} > sum_{i-1}$,那么$(sum_{i-1},\frac{a_i}{2}]$就是一段缺口。因为已经排过序了,所以这段缺口是无法用其它方式补上的。

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n;
ll a[N],sum[N],ans;
ll div2(ll x)
{
    return (x-1>>1)+1;
}

int main()
{
    n=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++)
    {
        if(div2(a[i])>sum[i-1])ans+=div2(a[i])-sum[i-1]-1;
        sum[i]=sum[i-1]+a[i];
    }
    cout<<sum[n]-ans<<endl;
    return 0;
}

C.计数

没有限制的话就是Catalan数。

设$dp[l][r]$为在前序遍历上的区间为$[l,r]$,以$l$为根的子树中的方案数。

用二维前缀和记录限制,枚举左右子树分配的大小转移即可。

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return x*f;
}
typedef long long ll;
const ll mod=1e9+7;
const int N=405;
int T,n,m,g[N][N],sum[N][N];
ll dp[N][N];
int get(int x,int y,int xx,int yy)
{
    return sum[xx][yy]-sum[x-1][yy]-sum[xx][y-1]+sum[x-1][y-1];
}
void work()
{
    n=read();m=read();
    memset(g,0,sizeof(g));
    memset(sum,0,sizeof(sum));
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        g[x][y]++;
    }
    for(int i=1;i<=n;i++)
    {
        dp[i][i]=1;
        for(int j=1;j<=n;j++)
            sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+g[i][j];
    }
    for(int len=2;len<=n;len++)
    {
        for(int i=1;i+len-1<=n;i++)
        {
            int j=i+len-1;
            if(!get(i,i+1,i,j))(dp[i][j]+=dp[i+1][j])%=mod;
            if(!get(i+1,i,j,i))(dp[i][j]+=dp[i+1][j])%=mod;
            for(int k=i+1;k<=j-1;k++)
                if(!get(i,i+1,i,k)&&!get(k+1,i,j,k))
                    (dp[i][j]+=dp[i+1][k]*dp[k+1][j])%=mod;
        }
    }
    printf("%lld\n",dp[1][n]);
    return ;
}

int main()
{
    T=read();
    while(T--)work();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Rorschach-XR/p/11741700.html