Codeforces Testing Round 14

A:The Way to Home

link:http://codeforces.com/contest/910/problem/A

题面:有每次最大跳跃距离d,只有一部分的点可以落脚,求最少几步达到终点D

 

Solution :预处理+贪心

用f[i]表示离点i最近的可落脚点,贪心即可(dp同理)

#include <bits/stdc++.h>

using namespace std;
int n,d,pre[105];
string s;

int main()
{
    cin >> n >> d >> s;
    n--;
    
    pre[0]=0;
    for(int i=1;i<s.size();i++)
        if(s[i]=='1') pre[i]=i;
        else pre[i]=pre[i-1];
        
    int cur=0,res=0;
    bool f=true;
    while(cur<n)
    {
        if(pre[min(cur+d,n)]==cur)
        {
            f=false;
            break;
        }
        cur=pre[min(cur+d,n)];
        res++;
    }
    
    if(!f) cout << -1;
    else cout << res;
    
    return 0;
}
Problem A

 

B. Door Frames

http://codeforces.com/contest/910/problem/B

题面:有4个长度为a和2个长度为b的木板,求最少用多少个长度为n的木板可以裁出所要求的所有木板

 

Solution A:分析法

这也是我用的方法,因为只有2个长度为b的木板,因此只有两种情况,一个n做2个b,或2个n做2个b,其余空间全部由a填满。

Tip:c++中自带的上下取整函数:floor()和ceil()

#include <bits/stdc++.h>

using namespace std;
typedef pair<float,float> P;
int n,a,b;

int main()
{
    cin >> n >> a >> b;
    
    if(n>=(a+a+b)*2) cout << 1;
    else if(n>=(a+a+b)) cout << 2;
    else
    {
        P n1,n2,n3;
        int res=1e9;
        n1.first=floor(n/a);n1.second=0;
        if(n>=2*b)
        {
            n3.first=floor((n-2*b)/a);
            n3.second=2;
            
            res=min(res,1+(int)ceil((4-n3.first)/n1.first));
        } 
        if(n>=b)
        {
            n2.first=floor((n-b)/a);
            n2.second=1;
            
            res=min(res,2+(int)ceil((4-2*n2.first)/n1.first));
        }
        cout << res;
    }
    
    return 0;
}
Solution A

 

Solution B:

因为真正会影响最终结果的是裁剪的顺序,因此对6个数全排列即可

在考虑最优解问题时,可以从枚举出每种可能的顺序下手

 

Tip:next_permutation()如一开始不排序,最终枚举的是该序列之后的排列

#include <bits/stdc++.h>

using namespace std;
#define pb push_back

int main()
{
    int n,a,b,res=1e9;
    cin >> n >> a >> b;
    vector<int> v;
    for(int i=0;i<4;i++) v.pb(a);
    v.pb(b);v.pb(b);
    
    sort(v.begin(),v.end());
    
    do
    {
        int l=n,cur=1;
        for(int i=0;i<6;i++)
            if(l-v[i]>=0) l-=v[i];
            else cur++,l=n-v[i];
        res=min(res,cur);
    }
    while(next_permutation(v.begin(),v.end()));
    cout << res;
    return 0;
}
Solution B

 

Solution C:递归

这也是我一开始未想到的,其实本应该是非常直观的思路

用dfs(x,y)返回还剩x个a,y个b最少要用几个n来组成,直接暴力

Tip:当有两层循环且内层循环当i=0时j要从1开始时,可以将起始条件设为j=(i==0)

#include <bits/stdc++.h>

using namespace std;
int n,a,b;

int dfs(int x,int y)
{
    int ret=10;
    if(!x && !y) return 0;
    for(int i=0;i<=x && i*a<=n;i++)
        for(int j=(i==0);j<=y && j*b+i*a<=n;j++)
        {
            ret=min(ret,dfs(x-i,y-j));
        }
    ret++;
    return ret;
}

int main()
{
    cin >> n >> a >> b;
    
    cout << dfs(4,2);
    return 0;
}
Solution C

 

Solution D:状压DP

Zscoder大神的写法,虽然没有必要,但代码技巧是值得学习的

先用only数组储存所有一个n能组成的情况,接下来进行状压DP

 

Tip: 1、当判断在二进制下i是否包含j时,使用(i&j)==j

       2、当表示在二进制下只在i中但不在j中的1时,使用i^j(前提:i包含j,否则表示的是两者不共同所有的1)

#include <bits/stdc++.h>

using namespace std;
#define pb push_back
int dp[(1<<10)];
int n,a,b;

int main()
{
    cin >> n >> a >> b;
    vector<int> v;
    for(int i=0;i<4;i++) v.pb(a);
    for(int i=0;i<2;i++) v.pb(b);
    for(int i=0;i<(1<<6)+10;i++) dp[i]=1e9;
    
    dp[0] = 0;
    vector<int> only;
    for(int i=1;i<(1<<6);i++)
    {
        int sum=0;
        for(int j=0;j<v.size();j++)
            if(i&(1<<j)) sum+=v[j];
        if(sum<=n)
        {
            dp[i]=1;only.pb(i);
        }
    }
    for(int i=1;i<(1<<6);i++)
        for(int z=0;z<only.size();z++)
        {
            int j=only[z];
            if((i&j)==j)
                dp[i]=min(dp[i],dp[j]+dp[(i^j)]);
        }
    
    cout<<dp[(1<<6)-1];
}
Solution D

 

C:Minimum Sum

link:http://codeforces.com/contest/910/problem/C

 

Solution:

先计算出每个字母要计算的总次数,同时记录其是否有可能为首位,接下来贪心

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<ll,bool> P;

int n;
P a[30];

int main()
{
    cin >> n;
    for(int i=1;i<=n;i++)
    {
        string s;cin >> s;
        
        ll time=1;
        for(int j=s.size()-1;j>=0;j--)
        {
            if(!j) a[s[0]-'a'].second=true;
            a[s[j]-'a'].first+=time;
            time*=10;
        }
    }
    
    sort(a,a+10,greater<P>());
    
    ll res=0,cur=1;
    bool used=false;
    for(int i=0;i<=9;i++)
    {
        if(!a[i].second && !used) used=true;
        else
        {
            res+=a[i].first*cur;
            cur++;
        }
    }
    cout << res;
    
    return 0;
}
Problem C

 

转载于:https://www.cnblogs.com/newera/p/8092803.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值