2020沈阳区域赛补题&总结

7月18号的比赛,一直拖着没补。想想就这样放着不太行,还是开个坑慢慢填吧

考前一个月备战期末没摸acm,最后rank85/265,罚时卡出ag线,大概就是报应吧。

D. Journey to Un'Goro

传送门

构造。

很关键的一个想法:令\(p_i\)表示从\(1\)\(i\)位置中\(r\)数量的奇偶性,\(i\)\(j\)\(r\)的数量为奇数的条件便是\(p_{i-1},p_j\)不同。(特别地,\(p_0\)为偶)

那么对于\(n\)的一种构造方式,考虑有\(x\)个奇数点,\(n+1-x\)个偶数点,那么题中要求的\((i,j)\)对数就是\(x*(n-x+1)\)。均值不等式,想要最大化合法对数就是使得奇偶点数为\(\lceil\frac{n+1}{2}\rceil\)\(\lfloor\frac{n+1}{2}\rfloor\)(谁大谁小都行),然后就排列就是了。由于从第\(0\)位开始且该位确定是偶,所以排列确定,你的\(br\)序列也就定了。排列中当前位与前一位不同,这一位就是\(r\),反之是\(b\)

那么dfs就行了,贪心从前往后做一位一位的做,在满足奇偶点的数量约束的前提下(\(\lceil\frac{n+1}{2}\rceil\)),优先保证当前位与前一位奇偶相同(也就是填\(b\)),搜到了100个答案就直接终止。

#include<bits/stdc++.h>
using namespace std;
int n,tot=0;
int ans[100005],num[2];
void dfs(int len)
{
    if(tot>=100)
        return;
    if(len>n)
    {
        for(int i=1;i<=n;i++)
        {
            if(ans[i]==ans[i-1])
                printf("b");
            else
                printf("r");
        }
        tot++;
        if(tot>=100)
            exit(0);
        printf("\n");
        return;
    }
    int p=ans[len-1];
    if(num[p]<n/2+1)
    {
        num[p]++;
        ans[len]=p;
        dfs(len+1);
        num[p]--;
    }
    p=p^1;
    if(num[p]<n/2+1)
    {
        num[p]++;
        ans[len]=p;
        dfs(len+1);
        num[p]--;
    }
}
int main()
{
    scanf("%d",&n);
    long long p=n;
    ans[0]=0;
    num[0]=1;
    num[1]=0;
    printf("%lld\n",(p+1ll)/2ll*(p/2ll+1ll));
    dfs(1);
    return 0;
}

H. The Boomsday Project

传送门
先考虑怎么暴力

显然你一定是把一张优惠卡用到不能用了(时间限制或次数限制)

将每次租车按时间排序,\(dp[i]\)表示恰好处理完前\(i\)次租车的最小花费,\(f[i][j]\)表示在第\(i\)次用第\(j\)张卡,能覆盖到的最后租车是那次,\(f\)数组可以二分查找来得出

转移:

\[dp[i+f[i+1][j]]=max(dp[i]+c,dp[i+f[i+1][j]]) \]

\[dp[i+1]=max(dp[i+1],dp[i]+r) \]

再考虑怎么优化掉这个\(log\)

注意到\(f\)数组具有单调性:

\[f[i+1][j]>=f[i][j] \]

事实上我们每次算\(f[i][j]\)时,只需要从\(f[i-1][j]\)开始递推,一个一个地往后挪即可

特别地,为了防止MLE,f数组需要使用滚动数组

#include<bits/stdc++.h>
using namespace std;
int n,m,r,p,q,cnt=0;
int d[505],k[505],c[505],rt[300005],f[2][505];
long long dp[300005];
int main()
{
    memset(f,0,sizeof(f));
    scanf("%d%d%d",&n,&m,&r);
    for(int i=1;i<=n;i++)
        scanf("%d%d%d",&d[i],&k[i],&c[i]);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&p,&q);
        for(int j=cnt+1;j<=cnt+q;j++)
        {
            rt[j]=p;
            dp[j]=1e18;
        }
        cnt+=q;
    }
    sort(rt+1,rt+1+cnt);
    dp[0]=0;
    rt[0]=0;
    for(int i=0;i<=cnt-1;i++)
    {
        dp[i+1]=min(dp[i+1],dp[i]+1ll*r);
        for(int j=1;j<=n;j++)
        {
            for(int l=f[0][j];l<=cnt;l++)
            {
                if(l-i<=k[j]&&rt[l]-rt[i+1]<=d[j]-1)
                    f[1][j]=l;
                else
                    break;
            }
            f[0][j]=f[1][j];
            dp[f[0][j]]=min(dp[i]+1ll*c[j],dp[f[0][j]]);
            //printf("%d %d %d %lld %lld\n",i,j,f[0][j],dp[i],dp[i+f[0][j]]);
        }
    }
    printf("%lld",dp[cnt]);
    return 0;
}
posted @ 2021-08-04 23:05  nanjoln0  阅读(122)  评论(0编辑  收藏  举报