2012 Multi-University Training Contest

本文深入探讨了数位DP与O(nlogn)算法在解决特定问题,如求解区间内具有特定性质数字的数量时的应用。通过实例分析,展示了如何利用这些算法高效解决问题,并提供了相应的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HDU 4352

数位dp结合o(nlogn)的最长严格递增子序列

给定一个数的价值为  将该数字看成一个由单个数字排列成的序列,其最长严格递增子序列的长度就是该数的价值

给定一个区间  求该区间内价值为k的有多少个

nlogn的最长严格递增子序列的求法可以自行百度

#include <stdio.h>
#include <string.h>
#define LL __int64
int dit[50],K;
LL dp[19][2049][11];
void init()
{
    for(int i=0;i<19;++i)
    {
        for(int j=0;j<(1<<10);++j)
        {
            for(int k=0;k<11;++k)
            {
                dp[i][j][k] = -1;
            }
        }
    }
}
LL dfs(int limit,int sta,int pos,int k)
{
    //printf("%d %d %d\n",sta,pos,k);
    if(pos<0)
        return k==K;
    if(!limit&&dp[pos][sta][K]!=-1)
        return dp[pos][sta][K];
    int end=limit?dit[pos]:9;
    LL sum=0;
    for(int i=0;i<=end;i++)
    {
        if(i==0&&sta==0)
        {
            sum+=dfs(limit&&(i==end),0,pos-1,k);
        }
        else
            if((1<<i)&sta)
        {
            sum+=dfs(limit&&(i==end),sta,pos-1,k);
        }
        else if((1<<i)>sta)
        {
            sum+=dfs(limit&&(i==end),sta|(1<<i),pos-1,k+1);
        }
        else
        {
            int nst=0;
            for(int j=i+1; j<=9; j++)
            {
                if((1<<j)&sta)
                {
                    nst=(sta|(1<<i))^(1<<j);
                    break;
                }
            }
            sum+=dfs(limit&&(i==end),nst,pos-1,k);
        }
    }
    if(!limit)
        dp[pos][sta][K]=sum;
    return sum;
}
LL cal(LL n)
{
    int cnt=0;
    while(n>0)
    {
        dit[cnt++]=n%10;
        n/=10;
    }
    return dfs(1,0,cnt-1,0);
}
int main()
{
    int t,ca=0;
    scanf ("%d",&t);
    init();
    while(t--)
    {
        LL l,r;
        ca++;
        scanf ("%I64d%I64d%d",&l,&r,&K);
        printf("Case #%d: %I64d\n",ca,cal(r)-cal(l-1));
    }
}
HDU 4357

该题可以推出结论 当字母多于3个时,其中任意两个可以互换

这样只需要特殊处理只有两个字母的情况就可以了


#include<stdio.h>
#include <string.h>
int main ()
{
    char s1[100],s2[100];
    int t;
    scanf ("%d",&t);
    for(int ca=1;ca<=t;ca++)
    {
        scanf ("%s%s",s1,s2);
        int len=strlen(s1);
        if(len>2)
        {
            int sum=0;
            for(int i=0;i<len;i++)
            sum+=(s1[i]-'a'+s2[i]-'a');
            if(sum&1)
            printf("Case #%d: NO\n",ca);
            else
            printf("Case #%d: YES\n",ca);
        }
        else
        {
            int ans1=s2[0]-s1[1]+52;
            int ans2=s2[1]-s1[0]+52;
            int ans3=s2[0]-s1[0]+52;
            int ans4=s2[1]-s1[1]+52;
            if((ans1==ans2&&(ans1&1))||(ans3==ans4&&(ans3%2==0)))
            printf("Case #%d: YES\n",ca);
            else
            printf("Case #%d: NO\n",ca);
        }
    }
}
HDU4359

这道是组合数学以及动态规划

由于2的n次方大于1到n-1次方的和

所以只需要将2的n次方放在右子树即可满足题目要求

剩下的就是分配子树节点个数 

没了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值