[欢乐赛]20171024

1.分火腿

考试时想用循环加特判写,最后发现写一个gcd就够了

#include<cstdio>

int gcd(int a,int b)
{
    int r=a%b;
    while(r!=0)
    {        
        a=b;
        b=r;
        r=a%b;
    }
    return b;
}
int main()
{
    freopen("hdogs.in","r",stdin);
    freopen("hdogs.out","w",stdout);
    int T,a,b,x,ans;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&a,&b);
        if(a%b==0){printf("0\n");continue;}
        a=a-b*(a/b);
        x=gcd(a,b);
        x=a/x;
        ans=b-1-(a-1)/x;
        printf("%d\n",ans);
    }
    return 0;
}

2.无聊的会议

用del不同颜色等腰三角形个数,不同色必然有两个异色点,可以用这两个异色点确定三角形然后去重并去掉等边三角形的重复计算。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int T,n;
char a[1000005];
ll calcu()
{
    ll ans=0;
    ans=(ll) n*((n-1)/2);
    if(n%3==0) ans-=n/3*2;
    return ans;
}
ll del()
{
    ll ans;
    if(n%2==1)
    {
        int s1=0,i,s0=0;
        for(i=0;i<n;i++)
        {
            if(a[i]=='0') s0++;
            else s1++;
        }
        ans=(ll)s1*s0*3;
        if(n%3==0)
        {
            s1=n/3; s0=n/3*2;
            for(i=0;i<n;i++)
            {
                if(a[i]!=a[(i+s1)%n]) ans--;
                if(a[i]!=a[(i+s0)%n]) ans--;
            }
        }
        return ans/2;
    }
    else
    {
        int i,s00=0,s01=0,s10=0,s11=0;
        for(i=0;i<n;i+=2)
        {
            if(a[i]=='0') s00++;
            else s01++;
        }
        for(i=1;i<n;i+=2)
        {
            if(a[i]=='0') s10++;
            else s11++;
        }
        ans=(ll)s00*s11*2; ans+=(ll)s01*s10*2;
        ans+=(ll)s00*s01*4; ans+=(ll)s10*s11*4;
        int n1,n2;
        n1=n/2;
        for(i=0;i<n;i++)
        {if(a[i]!=a[(i+n1)%n]) ans--;}
        if(n%3==0)
        {
            int s1=n/3,s0=n/3*2;
            for(i=0;i<n;i++)
            {
                if(a[i]!=a[(i+s1)%n]) ans--;
                if(a[i]!=a[(i+s0)%n]) ans--;
            }
        }
        return ans/2;
    }
}
int main()
{
    freopen("meeting.in","r",stdin);
    freopen("meeting.out","w",stdout);
    scanf("%d",&T);
    int k;
    for(k=1;k<=T;k++)
    {
        scanf("%s",a); n=strlen(a);
        printf("Case %d: %lld\n",k,calcu()-del());
    }
    return 0;
}

3.班服

此题在考试时用for循环暴力,过了40%。

正确方法:状压DP

数据n范围较小(10),可以用二进制数来表示n被选择的状态,末状态是(1<<n)-1。要处理班级与服装的关系,需在读入时让服装来存储班级的信息才能方便转移。

参考代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int mod=1e9+7;
int T,n,x,mp[110][110],f[110][1<<11];
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        memset(mp,0,sizeof(mp));
        memset(f,0,sizeof(f));
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
        {
            while(1)
            {
                scanf("%d",&x);
                mp[x][++mp[x][0]]=i;
                char ch=getchar();
                if(ch=='\n') break;
            }
        }
        f[0][0]=1;
        for(int i=1;i<=100;++i)
            for(int j=0;j<(1<<n);++j)
            {
                f[i][j]+=f[i-1][j];
                for(int k=1;k<=mp[i][0];++k)
                if(j&(1<<mp[i][k]-1))
                    (f[i][j]+=f[i-1][j-(1<<mp[i][k]-1)])%=mod;
            }
        printf("%d\n",f[100][(1<<n)-1]);
     }
     return 0;
}

 

posted @ 2017-10-25 17:28  wisdom_jie  阅读(297)  评论(0编辑  收藏  举报