超级码力在线编程大赛初赛 第三场

1.最大公倍数

打表找规律,发现答案肯定是max(lcm(b,b-1,b-2),lcm(b,b-1,b-3),lcm(b-1,b-2,b-3),lcm(b,b-2,b-3));

class Solution {
public:
    /**
     * @param a: Left margin
     * @param b: Right margin
     * @return: return the greatest common multiple
     */
     long long gcd(long long x,long long y)
    {
    return y==0?x:gcd(y,x%y);   
    }
    long long greatestcommonmultiple(int a, int b) {
        // write your code here
        long long aa=(long long)a;
        long long bb=(long long)b;
        if(aa==bb-2)
        {
            long long tmp=bb*(bb-1)/gcd(bb,bb-1);
            return tmp*(bb-2)/gcd(tmp,bb-2);
        }
        long long ma=0;
        long long tmp;
        tmp=bb*(bb-1)/gcd(bb,bb-1);
        ma=max(ma,tmp*(bb-2)/gcd(tmp,bb-2));
        tmp=bb*(bb-2)/gcd(bb,bb-2);
        ma=max(ma,tmp*(bb-3)/gcd(tmp,bb-3));
        tmp=(bb-1)*(bb-2)/gcd(bb-1,bb-2);
        ma=max(ma,tmp*(bb-3)/gcd(tmp,bb-3));
        tmp=bb*(bb-1)/gcd(bb,bb-1);
        ma=max(ma,tmp*(bb-3)/gcd(tmp,bb-3));
        return ma;
    }
};

2.房屋染色

动态规划,dp[i][j][0]表示以i为结尾染成j颜色没有步行街的最小花费,dp[i][j][1]表示以i为结尾染成j颜色有步行街的最小花费。dp[i][c1][0]=min(dp[i-1][c2][0]+costs[i][c1]),没有步行街时,必须和前一个颜色不同,且前一个也是没有步行街的状态。dp[i][c1][1]=min(dp[q][c1][0]+val[i][c1]-val[q][c1]),dp[i][c1][1]=min(dp[i-1][c2][1]+costs[i][c1])如果有步行街时,可以由之前没有步行街的状态推出,此时利用前缀和找到最小花费的转移状态。也可以由有步行街的状态推出,这与之前没有步行街时一样。

class Solution {
public:
    /**
     * @param costs: costs of paint ith house into color j
     * @param t: maximum length of street
     * @return: minimum costs of painting all houses
     */
     int inf=0x3f3f3f3f;
     int dp[105][105][2];
     int val[105][105];
    int paintHouseIII(vector<vector<int>> &costs, int t) {
        // Write your code here.
    memset(dp,inf,sizeof(dp));
    int n=costs.size();
    int k=costs[0].size();
    for(int j = 1; j <= k; ++j)
    dp[1][j][0] = dp[1][j][1] = costs[0][j-1];//初始化
    for(int i=1;i<=n;++i)
    for(int j=1;j<=k;++j)
    {
        if(i==1)
        val[i][j]=costs[i-1][j-1];
        else
        val[i][j]=val[i-1][j]+costs[i-1][j-1];
    }
    for(int i=2;i<=n;++i)
    for(int j=1;j<=k;++j)
    {
        for(int p=1;p<=k;++p)
        {
            if(p!=j)//不能与之前构成步行街
            {
                dp[i][j][0]=min(dp[i][j][0],dp[i-1][p][0]+costs[i-1][j-1]);
                dp[i][j][1]=min(dp[i][j][1],dp[i-1][p][1]+costs[i-1][j-1]);
            }
        }
        //能与之前构成步行街
        for(int q=i-1;q>=1;q--)
        {
            if(i-q+1>t)
            break;
            dp[i][j][1]=min(dp[i][j][1],dp[q][j][0]+val[i][j]-val[q][j]);
        }
    }
    int ans=inf;
    for(int j=1;j<=k;++j)
    ans=min(ans,min(dp[n][j][0],dp[n][j][1]));
    return ans;
    }
};

3.字符串游戏

反尼姆博弈,我们发现可以把问题转化为反尼姆博弈,26个字母分为26个石堆,每次可以从任意一堆拿出任意个石子(至少一个),拿走最后一个石子的失败。按反尼姆博弈求解即可。

class Solution {
public:
    /**
     * @param s: a string for this game 
     * @return: return whether Alice can win this game
     */
     int a[26];
    bool stringGame(string &s) {
        // Write your code here.
        memset(a,0,sizeof(a));
        int ans=0;
        int num=0;
        for(int i=0;i<s.size();++i)
        {
            a[s[i]-'a']++;
        }
        for(int i=0;i<26;i++)
         {
             if(a[i])
             ans^=a[i];
             if(a[i]>1)
             num=1;
         }
         if(num)
         {
             if(ans==0)
             return false;
             else 
             return true;
         }
         else
         {
             if(ans==0)
             return true;
             else
             return false;
         }
    }
};

4.完美字符串

我们发现,无论什么情况只要把连续的0变为1就是最优的。

class Solution {
public:
    /**
     * @param s: string need to be transformed
     * @param k: minimum char can be transformed in one operation
     * @return: minimum times of transforming all char into '1'
     */
    int perfectString(string &s, int k) {
        // Write your code here.
        int len=0;
        int ans2=0;
        for(int i=0;i<s.size();++i)
        {
            if(s[i]=='1')
            {
                ans2+=len/k+(len%k!=0);
                len=0;
            }
            else
            len++;
        }
        ans2+=len/k+(len%k!=0);
        return ans2;
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值