《Codeforces Round #667 (Div. 3)》

A:签到题

复制代码
// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<string,int> pii;
const int N = 1e5+5;
const int M = 2e5+5;
const LL Mod = 199999;
#define rg register
#define pi acos(-1)
#define INF 1e9
#define CT0 cin.tie(0),cout.tie(0)
#define IO ios::sync_with_stdio(false)
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline LL read(){
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    void print(int x){
        if(x < 0){x = -x;putchar('-');}
        if(x > 9) print(x/10);
        putchar(x%10+'0');
    }
}
using namespace FASTIO;
void FRE(){/*freopen("data1.in","r",stdin);
freopen("data1.out","w",stdout);*/}
 
int main()
{
    int ca;ca = read();
    while(ca--)
    {
        int a,b;a = read(),b = read();
        if(a > b) swap(a,b);
        int dis = b-a;
        int ma = dis/10;
        if(ma*10 == dis) printf("%d\n",ma);
        else printf("%d\n",ma+1);
    }
    //system("pause");
}
View Code
复制代码

B:这里假设了一下减去个值为t0,然后求出的乘积为一个开口向下的二次函数。

那么要最小化乘积,显然是在两边,也就是极限的两个位置,那么就是先让x尽可能小,然后让y尽可能小,求一下两者之间的最小即可

复制代码
// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<string,int> pii;
const int N = 1e5+5;
const int M = 2e5+5;
const LL Mod = 199999;
#define rg register
#define pi acos(-1)
#define INF 1e9
#define CT0 cin.tie(0),cout.tie(0)
#define IO ios::sync_with_stdio(false)
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline LL read(){
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    void print(int x){
        if(x < 0){x = -x;putchar('-');}
        if(x > 9) print(x/10);
        putchar(x%10+'0');
    }
}
using namespace FASTIO;
void FRE(){/*freopen("data1.in","r",stdin);
freopen("data1.out","w",stdout);*/}

LL slove(LL a,LL b,LL x,LL y,LL n)
{
    LL dis1 = min(n,a-x);
    a -= dis1;
    n -= dis1;
    LL dis2 = min(n,b-y);
    b -= dis2;
    return a*b;
}
int main()
{
    int ca;ca = read();
    while(ca--)
    {
        LL a,b,x,y,n;
        a = read(),b = read(),x = read(),y = read(),n = read();
        LL ans = slove(a,b,x,y,n);
        ans = min(ans,slove(b,a,y,x,n));
        printf("%lld\n",ans);
    }
   // system("pause");
}
View Code
复制代码

C:可以发现,在给定的两个值中间能插入越多的数,差距就会越大,然后剩余要插的就会越少。

那么我们就去找可以在中间插入多少,然后就找到了差距,然后先向小的方向插剩余的,然后再插大的方向

复制代码
// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<string,int> pii;
const int N = 1e5+5;
const int M = 2e5+5;
const LL Mod = 199999;
#define rg register
#define pi acos(-1)
#define INF 1e9
#define CT0 cin.tie(0),cout.tie(0)
#define IO ios::sync_with_stdio(false)
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline LL read(){
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    void print(int x){
        if(x < 0){x = -x;putchar('-');}
        if(x > 9) print(x/10);
        putchar(x%10+'0');
    }
}
using namespace FASTIO;
void FRE(){/*freopen("data1.in","r",stdin);
freopen("data1.out","w",stdout);*/}

int main()
{
    int ca;ca = read();
    while(ca--)
    {
        int n,x,y;n = read(),x = read(),y = read();
        n -= 2;
        vector<int> ans;
        ans.push_back(x);
        if(n == 0) ans.push_back(y);
        else
        {
            int dis = y-x,ma = 0;
            int m = sqrt(dis);
            for(rg int i = 1;i <= dis-1;++i)
            {
                if(dis%i == 0 && dis/i-1 <= n)
                {
                    ma = i;
                    break;
                }
            }
            if(ma == 0)
            {
                ans.push_back(y);
                int dis = y-x;
                for(rg int i = x-dis;i > 0 && n > 0;i -= dis) ans.insert(ans.begin(),i),n--;
                for(rg int i = y+dis;n > 0;i += dis) ans.push_back(i),n--;
            }
            else
            {
                int dis = ma;
                for(rg int i = x+dis;i < y;i += dis) ans.push_back(i),n--;
                for(rg int i = x-dis;i > 0 && n > 0;i -= dis) ans.insert(ans.begin(),i),n--;
                for(rg int i = y+dis;n > 0;i += dis) ans.push_back(i),n--;
                ans.push_back(y);
            }
        }
        for(rg int i = 0;i < ans.size();++i) printf("%d%c",ans[i],i == ans.size()-1 ? '\n' : ' ');
    }
    //system("pause");
}
View Code
复制代码

D:注意题目,满足小于等于即可。

模拟进制转化,从最小位开始向上进位,每次进位后都满足减去部分值。

当<=时就退出,注意中途记录答案值,不然最后的话,要把值进完再找最后的值相减,很麻烦。

证明一下为什么这样肯定是最小。

因为我们是不断从小开始进位,数值是在不断增大,但是现在最低位都为0了,如果去增加最低位,显然不会对答案产生贡献,那么,就满足增加最高位之后,第一次满足的肯定是最小。(有点口胡~)

复制代码
// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<string,int> pii;
const int N = 1e5+5;
const int M = 2e5+5;
const LL Mod = 199999;
#define rg register
#define pi acos(-1)
#define INF 1e9
#define CT0 cin.tie(0),cout.tie(0)
#define IO ios::sync_with_stdio(false)
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline LL read(){
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    void print(int x){
        if(x < 0){x = -x;putchar('-');}
        if(x > 9) print(x/10);
        putchar(x%10+'0');
    }
}
using namespace FASTIO;
void FRE(){/*freopen("data1.in","r",stdin);
freopen("data1.out","w",stdout);*/}

int a[25],len;
int Get_dig()
{
    int sum = 0;
    for(rg int i = 1;i <= len;++i) sum += a[i];
    return sum;
}
int main()
{
    int ca;ca = read();
    while(ca--)
    {
        memset(a,0,sizeof(a));
        string s;cin >> s;
        int ss;ss = read();
        len = s.size();
        for(rg int i = 0;i < len;++i) a[len-i] = s[i]-'0';
        int dig = Get_dig();
        if(dig <= ss) printf("0\n");
        else
        {
            LL ans = 0,ma = 1;
            for(rg int i = 1;i <= len;++i,ma *= 10)
            {
                ans += (10-a[i])*ma;
                a[i] = 0;
                a[i+1]++;
                if(Get_dig() <= ss) break;
            }
            printf("%lld\n",ans);
        }
    }
  //  system("pause");
}
View Code
复制代码

E:这题我感觉不是很难,一发就过了。

题意很显然,我们先排序去重。map记录下每个位置重复的个数。

然后我们可以去枚举第一个放的线段,显然我们枚举的是左边界,并且显然这个左边界在存在的点上更优。

第一条显然的覆盖点数我们可以二分+前缀和求出。

然后我们再去枚举第二个放的线段,显然这个线段的左起点应该在当前区间右边界外更优。

那么此时,我们枚举两个的复杂度为n^2。这显然会T。

但是,我们可以先处理出dp[i]表示i~n里选择某个点为起点的最优覆盖长度的最大值。

然后枚举第一个线段时,对于第二个线段就可以高效求出了。

复制代码
// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<string,int> pii;
const int N = 2e5+5;
const int M = 2e5+5;
const LL Mod = 1e9+7;
#define rg register
#define pi acos(-1)
#define INF 1e9
#define CT0 cin.tie(0),cout.tie(0)
#define IO ios::sync_with_stdio(false)
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline LL read(){
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    void print(int x){
        if(x < 0){x = -x;putchar('-');}
        if(x > 9) print(x/10);
        putchar(x%10+'0');
    }
}
using namespace FASTIO;
void FRE(){/*freopen("data1.in","r",stdin);
freopen("data1.out","w",stdout);*/}

int x[N],y[N];
LL sum[N],dp[N];//dp[i]-i~n的最优价值
int main()
{
    int ca;ca = read();
    while(ca--)
    {
        int n,k;n = read(),k = read();
        unordered_map<int,int> mp;
        for(rg int i = 1;i <= n;++i) x[i] = read(),mp[x[i]]++;
        for(rg int i = 1;i <= n;++i) y[i] = read();
        sort(x+1,x+n+1);
        int len = unique(x+1,x+n+1)-x-1;
        sum[0] = 0;
        for(rg int i = 1;i <= len;++i) sum[i] = sum[i-1]+mp[x[i]];
        int mx = x[len];
        dp[len+1] = 0;
        for(rg int i = len;i >= 1;--i)
        {
            LL pos = x[i]+k,ma;
            if(pos >= mx) ma = sum[len]-sum[i-1];
            else 
            {
                int pt = upper_bound(x+1,x+len+1,pos)-x;
                ma = sum[pt-1]-sum[i-1];
            } 
            dp[i] = max(dp[i+1],ma);
        }
        LL ans = 0;
        for(rg int i = 1;i <= len;++i)
        {
            int pos = x[i]+k;
            LL tmp1,tmp2;
            if(pos >= mx) 
            {
                tmp1 = sum[len]-sum[i-1];
                tmp2 = 0;
            }
            else
            {
                int pt = upper_bound(x+1,x+len+1,pos)-x;
                tmp1 = sum[pt-1]-sum[i-1];
                tmp2 = dp[pt];
            }
            ans = max(ans,tmp1+tmp2);
        }
        printf("%lld\n",ans);
    }    
   // system("pause");    
}
View Code
复制代码

F:第一眼就感觉是dp,无从下手。太菜了太菜了~~

注意t只有两个字符。

定义dp[i][j][k]表示前i个位置,变换了j个数,k个t0的最多方案数。

注意的是要判断两个字符相同时的影响。转移的话就三种,si不变,si变t0,si变t1。注意这里的方案都算的是到i位置的方案数。

对于i~n的方案数都还未计算,然后可以发现,到了n位置,n+1位置可能才会记录到n位置的方案数,所以最后也要计算到n+1位置。

复制代码
// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<string,int> pii;
const int N = 2e5+5;
const int M = 2e5+5;
const LL Mod = 1e9+7;
#define rg register
#define pi acos(-1)
#define INF 1e9
#define CT0 cin.tie(0),cout.tie(0)
#define IO ios::sync_with_stdio(false)
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline LL read(){
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    void print(int x){
        if(x < 0){x = -x;putchar('-');}
        if(x > 9) print(x/10);
        putchar(x%10+'0');
    }
}
using namespace FASTIO;
void FRE(){/*freopen("data1.in","r",stdin);
freopen("data1.out","w",stdout);*/}

LL dp[205][205][205];//dp[i][j][k]-前i个位置更改了j个字符,t0的数量为k时的方案数
int main()
{
    int n,k;n = read(),k = read();
    string s;cin >> s;
    string t;cin >> t;
    char t0 = t[0],t1 = t[1];
    memset(dp,-0x3f,sizeof(dp));
    LL low = dp[0][0][0];
    LL ans = 0;
    dp[1][0][0] = 0;
    for(rg int i = 1;i <= n;++i)
    {
        char ch = s[i-1];
        for(rg int j = 0;j <= k;++j)
        {
            for(rg int z = 0;z <= n;++z)
            {
                if(dp[i][j][z] == low) continue;
               // printf("i is %d j is %d z is %d\n",i,j,z);
                int num1 = (ch == t0);
                int num2 = (ch == t1);
                dp[i+1][j][z+num1] = max(dp[i+1][j][z+num1],dp[i][j][z]+num2*z);//不变si
                if(j < k)//一定要<,当=时无法再变换
                {
                    int same = (t0 == t1);
                    dp[i+1][j+1][z+1] = max(dp[i+1][j+1][z+1],dp[i][j][z]+same*z);//变成t1
                    dp[i+1][j+1][z+same] = max(dp[i+1][j+1][z+same],dp[i][j][z]+z);//变成t1
                }
            }
        }
    }
    for(rg int i = 1;i <= n+1;++i)
        for(rg int j = 0;j <= n;++j)
            for(rg int k = 0;k <= n;++k) ans = max(ans,dp[i][j][k]);
    printf("%lld\n",ans);
    //system("pause");    
}
View Code
复制代码

 

posted @   levill  阅读(164)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示