2024牛客寒假算法基础集训营2个人补题题解(K、D)

比赛链接:2024牛客寒假算法基础集训营2

K、Tokitsukaze and Password (easy)

题面看着很难实际上只要暴力的东西,赛时看了眼题面就溜了血亏
爆搜,枚举abcd和_可能的值,枚举的情况只有98769=27216种。判断按照枚举出的对应值排列出的密码是否满足条件,满足就ans++
写完以后发现大概也不需要dfs,直接五层循环就行。

ac代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
const int inf=1e18;
const int M=1e9+7;
bool vis[20];
map<int,int> mp;
int v[N];
int n;
int lim;
int ans;
string s;
void dfs(int cnt)
{
    if(cnt==5)
    {
        int p=0;
        string now;
        for(int i=0;i<n;i++)
        {
            char c;
            if(isdigit(s[i]))
                now+=s[i],p=p*10+s[i]-'0';
            else
            {
                if(isalpha(s[i]))
                    c=v[s[i]-'a'+1]+'0';
                else c=v[5]+'0';
                now+=c;
                p=p*10+(c-'0');
            }
        }
        if(n==1&&p==0&&mp[p]==0)
            ans++,mp[p]=1;
        else if(p%8==0&&p<=lim&&mp[p]==0&&now[0]!='0')
            ans++,mp[p]=1;
        return ;
    }
    for(int i=0;i<=9;i++)
    {
        if(cnt!=4)
        {
            if(vis[i]==0)
            {
                v[cnt+1]=i;
                vis[i]=1;
                dfs(cnt+1);
                vis[i]=0;
            }
        }
        else
        {
            v[cnt+1]=i;
            dfs(cnt+1);
        }
    }
}
signed main() {
    int t;
    cin >>t;
    while(t--)
    {
        memset(vis,0,sizeof(vis));
        mp.clear();
        cin >>n;
        cin >>s>>lim;
        ans=0;
        dfs(0);
        cout<<ans<<'\n';
    }
    return 0;
}





D、Tokitsukaze and Slash Draw

需要考虑的只有居合卡位置,先后是怎么摆的及其他卡的位置不需要考虑,很明显的多重背包,而且对于某一张卡来说最多使用n次,n次以上一定会发生位置的重复,但是如果直接上多重背包模板时间复杂度会来到O(m2n)会t掉。
预处理up数组,定义up[i]为使当前位置上升i位置的最小花费。
定义dp[i][j]为在当前居合卡的位置为j时最多移动了i个位置的最小花费。
状态转移:dp[i][(i+j)]=min(dp[i][(i+j)],dp[i1][j]+up[i])
最后答案就是dp[n][0](当前居合卡在0位置时,最多向上移动了n个位置的最小花费)
时间复杂度:O(mn+n2)
还有图论做法和别的dp做法,但是脑子不太好使暂时只搞懂了这种(
自己的ac代码是特判了(i+j)%n=0的时候让它等于n,不过实测不搞特判也能过,内循环初始值设为0就行。

ac代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
const int inf=1e18;
const int M=1e9+7;
int up[5050];
int dp[5050][5050];
signed main() {
    int t;
    cin >>t;
    while(t--)
    {
        int n,m,k;
        cin >>n>>m>>k;
       // k-=1;
        for(int i=0;i<=max(n,m);i++)
        {
            for(int j=0;j<=max(n,m);j++)
                dp[i][j]=up[j]=inf;
        }
        for(int i=1;i<=m;i++)
        {
            int p,cost;
            cin >>p>>cost;
            for(int j=1;j<=n;j++)
            {
                int next=(j*p)%n;
                if(next==0) next=n;
                up[next]=min(up[next],cost*j);
            }
        }
        dp[0][k]=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
                dp[i][j]=dp[i-1][j];
            for(int j=1;j<=n;j++)
            {
                int next=(i+j)%n;
                if(next==0) next=n;
                dp[i][next]=min(dp[i][next],dp[i-1][j]+up[i]);
            }
        }
        if(dp[n][n]!=inf)
            cout<<dp[n][n]<<'\n';
        else cout<<-1<<'\n';
    }
    return 0;
}


posted @   Ritsuki  阅读(151)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示