codeforces round231 DIV2

   A:Counting Sticks 枚举

给一个用|组成的表达式,问是否可以移动一个|使得等式满足,并且每一项大于等于1.

分情况讨论就行,注意不要出现0.

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll;
char s[1000];
int a[5];
int main()
{
//    freopen("in.txt","r",stdin);
    gets(s);
    memset(a,0,sizeof a);
    int l=strlen(s);
    int ct=0;
    int sp=0;
    for (int i=0; i<l; i++)
    {
        if (s[i]=='|') sp++;
        else
        if (s[i]=='+')
        {
            a[0]=sp;
            sp=0;
        }
        else if (s[i]=='=')
        {
            a[1]=sp;
            sp=0;
        }
    }
    a[2]=sp;
    if (a[1] && a[0] && a[0]+a[1]==a[2])
    {
        puts(s);
    }
    else if (a[0]+1+a[1]==a[2]-1 && a[1])
    {
            for (int i=0; i<a[0]+1; i++) printf("|");
            printf("+");
            for (int i=0; i<a[1]; i++) printf("|");
            printf("=");
            for (int i=0; i<a[2]-1; i++) printf("|");
            printf("\n");

    }
    else if (a[0]+a[1]+1==a[2]-1 && a[0])
    {
         for (int i=0; i<a[0]; i++) printf("|");
            printf("+");
            for (int i=0; i<a[1]+1; i++) printf("|");
            printf("=");
            for (int i=0; i<a[2]-1; i++) printf("|");
            printf("\n");
    }
    else if(a[0]>1 && a[0]-1+a[1]==a[2]+1)
    {
         for (int i=0; i<a[0]-1; i++) printf("|");
            printf("+");
            for (int i=0; i<a[1]; i++) printf("|");
            printf("=");
            for (int i=0; i<a[2]+1; i++) printf("|");
            printf("\n");
    }
    else if(a[1]>1 && a[1]-1+a[0]==a[2]+1)
    {
         for (int i=0; i<a[0]; i++) printf("|");
            printf("+");
            for (int i=0; i<a[1]-1; i++) printf("|");
            printf("=");
            for (int i=0; i<a[2]+1; i++) printf("|");
            printf("\n");
    }
    else puts("Impossible");

    return 0;
}



B,Very Beautiful Number 枚举

构造一个p位数a1a2a3a4...ap,满足这个数乘x等于apa1a2a3a4...ap-1。

容易发现最后一位确定的话,前面的所有位置都可以递推出来,所以枚举最后一位1--9,最后判一下第一位不是0就可以了。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
int n,p,x;
int a[2001000],b[2001000];
int main()
{
    while(~scanf("%d%d",&p,&x))
    {
        int cp=0;
        bool ft=false;
        for (int i=1; i<=9; i++)
        {
            cp=0;
            a[p]=i;
            for (int j=p-1; j>=1; j--)
            {
                a[j]=cp+a[j+1]*x;
                cp=a[j]/10;
                a[j]%=10;
            }
            if (a[1]*x+cp==a[p] && a[1]!=0)
            {

                for (int i=1; i<=p; i++)
                printf("%d",a[i]);
                printf("\n");
                ft=true;
                break;
            }

        }
        if (!ft) puts("Impossible");
    }
    return 0;
}


C  Dominoes 贪心构造

N*M个多米诺骨牌,每个牌形同00,11,01,10(01,10可以互相转换)。所有的骨牌可以构造成一个N*2M的矩阵,问如何构造可以使的每一列的和的最大值尽可能小。

这题主要是处理01的情况,读数据的时候统计一下00,01,11的数量(01,10归为一类),然后构造的时候两行两行的构造,每次添加一组01/10的情况,直到01的数量小于2,然后从下到上从右到左填充11,省下的全是00.

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
int n,m;
int xx,xy,yy;
char s[5];
int ans[1100][1100];
int main()
{
//    freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&n,&m))
    {
        memset(ans,0,sizeof ans);
        xx=xy=yy=0;
        for (int i=1; i<=n; i++)
         for (int j=1; j<=m; j++)
         {
            scanf("%s",&s);
            if (s[0]=='1' && s[1]=='1') xx++;
            else if (s[0]=='0' && s[1]=='0') yy++;
            else xy++;
         }
        if (n==1)
        {
            for (int i=1; i<=n; i++)
            if (xx) ans[1][i]=4,xx--;
            else if (xy) ans[1][i]=3, xy--;
            else ans[i][1]=0,yy--;
        }
        else
        {
            for (int i=1; i<=n; i+=2)
             for (int j=1; j<=m; j++)
             {
                 if (xy>=2)
                 {
                     ans[i][j]=2;
                     ans[i+1][j]=3;
                     xy-=2;
                 }
             }
            for (int i=n; i>=1; i--)
             for (int j=m; j>=1; j--)
             if (ans[i][j]==0)
             {
                 if (xx) ans[i][j]=4,xx--;
                 else if (xy) ans[i][j]=2,xy--;
                 else ans[i][j]=0,yy--;
             }
        }

        for (int i=1; i<=n; i++)
         {
             for (int j=1; j<=m; j++)
             if (ans[i][j]==4) cout<<"11 ";
             else if (ans[i][j]==3) cout<<"10 ";
             else if (ans[i][j]==2) cout<<"01 ";
             else cout<<"00 ";
             cout<<endl;
         }
    }
    return 0;
}


Physical Education and Buns  枚举

n个人每个人有一个身高,现在有两种馒头,第一种吃一个身高+1,第二种吃一个身高-1,问在允许调换顺序的情况下,吃馒头最多的人最少要吃多少个,可以使得所有人的身高满足不减的等差数列,并且输出数列的最小值和步长。思路的话先从小打到排序,然后直接枚举步长0--20000,每个步长对每个数处理出一个变化量记为数组B,B中绝对值的最大值就是吃馒头最多的人吃的数量,但是我们可以对这个数组整体+或者-从而降低这个最大值,而up(abs(max-min)/2)就是调整后的最大值,之后根据这个值求出变化后的最小的人的身高就可以了。复杂度O(20000*1000),cf上跑了46ms,所以说cf上见到复杂的1e7的题就放心的写吧...

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
int n,m;
int a[2020];
int b[2020];
int last;
int work(int bc)
{
    int res=0;
    last=a[0];
    b[0]=0;
        int mi=0,mx=0;
        for (int i=1; i<n; i++)
        {
            b[i]=last+bc-a[i];
            last=last+bc;
            mi=min(mi,b[i]);
            mx=max(mx,b[i]);
        }
    int tp=abs(mi-mx);
    res=tp/2;
    if (tp&1) res++;
    last=a[0]+res-mx;
    return res;
}
int main()
{
//    freopen("in.txt","r",stdin);
    while(~scanf("%d",&n))
    {
        for (int i=0; i<n; i++)
        scanf("%d",&a[i]);
        sort(a,a+n);
        int l=0,r=20000;
        int mid;
        int ans=30000;
        int t1,t2;
        for (int i=0; i<=20000; i++)
        if (work(i)<ans)
        {
            ans=work(i);
            t1=last;
            t2=i;
        }
        cout<<ans<<endl<<t1<<" "<<t2<<endl;
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值