2013 Multi-University Training Contest 6

13 篇文章 0 订阅
12 篇文章 0 订阅

1001 Cut Pieces

我们没过的版刷题,可是看了标程后发现我们确实不会,而且最多的排布方式只限于一大一小,我们一开始YY的大的放中间,小的放两边根本是错误的,小数据可能还没什么错,大数据就会发现错误。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#define N 1000000007
using namespace std;
inline void RD(int &ret)
{
    char c;
    do
    {
        c=getchar();
    }
    while(c<'0'||c>'9');
    ret=c-'0';
    while((c=getchar())>='0'&&c<='9')
    {
        ret=ret*10+(c-'0');
    }
}
inline void OT(int a)
{
    if(a>=10)
    {
        OT(a/10);
    }
    putchar(a%10+'0');
}
long long a[1000001],b[1000001],p[1000001],q[1000001];
int main()
{
    int n,i,t,j,l,r,m;
    long long sum,ans;
    RD(t);
    while(t--)
    {
        scanf("%d",&n);
        for(i=0;i<n;++i)
        {
            scanf("%I64d",&a[i]);
        }
        sort(a,a+n);
        reverse(a,a+n);//从大到小排列
        j=0;
        for(i=1;i<n;i+=2)//将a的值一大一小开始赋值到b中
        {
            b[i]=a[j++];
        }
        //j=0;
        for(i=0;i<n;i+=2)
        {
            b[i]=a[j++];
        }
        p[0]=q[n]=1;
        for(i=0;i<n;++i)
        {
            p[i+1]=p[i]*b[i]%N;//构造数列从前乘到后的数
        }
        for(i=n;i>0;--i)
        {
            q[i-1]=q[i]*b[i-1]%N;//构造数列从后乘到前的数
        }
        sum=0;
        for(i=0;i<n-1;++i)
        {
            l=i;
            r=i+1;
            if(b[l]>b[r])
            {
                m=l;
            }
            else
            {
                m=r;
            }
            sum=(sum+p[m]*q[m+1])%N;//标程上的方法,只去掉bm
        }
        ans=n*p[n]%N;
        ans=(ans-sum+N)%N;//总数减去重复的
        printf("%I64d\n",ans);
    }
    return 0;
}

1004 Integer Partition

这题是之前第五场Partition的扩展,当时只是了解了五角数定理,但没有深入探究,结果这题就是对原先的P(n)在做一次递推运算,只是每次加上或者减去的项为p(n-j*(3*j+-1)*k/2)。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#define N 1000000007
using namespace std;
inline void RD(int &ret)
{
    char c;
    do
    {
        c=getchar();
    }
    while(c<'0'||c>'9');
    ret=c-'0';
    while((c=getchar())>='0'&&c<='9')
    {
        ret=ret*10+(c-'0');
    }
}
inline void OT(int a)
{
    if(a>=10)
    {
        OT(a/10);
    }
    putchar(a%10+'0');
}
long long a[100005];
void f()//递推式
{
    int i,j;
    long long sum;
    a[0]=1;
    a[1]=1;
    a[2]=2;
    for(i=2; i<=100000; ++i)
    {
        sum=0;
        for(j=1; (i-j*(3*j-1)/2)>=0||(i-j*(3*j+1)/2)>=0; j++)
        {
            if(j%2==1)
            {
                if((i-j*(3*j-1)/2)>=0)
                {
                    sum=(sum+a[(i-j*(3*j-1)/2)])%N;//注意不能写+=,不然会产生溢出错误,(不管你是longlong还是int)
                }
                if((i-j*(3*j+1)/2)>=0)
                {
                    sum=(sum+a[(i-j*(3*j+1)/2)])%N;
                }
            }
            else
            {
                if((i-j*(3*j-1)/2)>=0)
                {
                    sum=(sum-a[(i-j*(3*j-1)/2)]+N)%N;//防止负数
                }
                if((i-j*(3*j+1)/2)>=0)
                {
                    sum=(sum-a[(i-j*(3*j+1)/2)]+N)%N;
                }
            }
        }
        a[i]=sum;
    }
}
int main()
{
    f();
    int t,n,j,k;
    long long sum;
    RD(t);
    while(t--)
    {
        scanf("%d%d",&n,&k);
        sum=a[n]%N;
        for(j=1; (n-j*(3*j-1)*k/2)>=0||(n-j*(3*j+1)*k/2)>=0; j++)//看过才知道只要乘就行,太悲剧了
        {
            if(j%2==0)
            {
                if((n-j*(3*j-1)*k/2)>=0)
                {
                    sum=(sum+a[(n-j*(3*j-1)*k/2)])%N;
                }
                if((n-j*(3*j+1)*k/2)>=0)
                {
                    sum=(sum+a[(n-j*(3*j+1)*k/2)])%N;
                }
            }
            else
            {
                if((n-j*(3*j-1)*k/2)>=0)
                {
                    sum=(sum-a[(n-j*(3*j-1)*k/2)]+N)%N;
                }
                if((n-j*(3*j+1)*k/2)>=0)
                {
                    sum=(sum-a[(n-j*(3*j+1)*k/2)]+N)%N;
                }
            }
        }
        printf("%I64d\n",sum%N);
    }
    return 0;
}

1008 MU Puzzle

全场唯一出的水题。

由于三种操作的存在,2^n-6k=sum(‘I的总数(可由U转换成)’),所以当sum=1或sum%6=2或者4时都是可行的

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
inline void RD(int &ret)
{
    char c;
    do
    {
        c=getchar();
    }
    while(c<'0'||c>'9');
    ret=c-'0';
    while((c=getchar())>='0'&&c<='9')
    {
        ret=ret*10+(c-'0');
    }
}
inline void OT(int a)
{
    if(a>=10)
    {
        OT(a/10);
    }
    putchar(a%10+'0');
}
int main()
{
    int t,i,l,f,sum;
    char a[1000001];
    RD(t);
    while(t--)
    {
        scanf("%s",a);
        l=strlen(a);
        f=0;
        if(a[0]!='M')
        {
            f=1;
        }
        sum=0;
        for(i=1;i<l;++i)
        {
            if(a[i]=='I')
            {
                sum+=1;
            }
            else if(a[i]=='U')//将U的数量也转化为I的数量
            {
                sum+=3;
            }
            else
            {
                f=1;
            }
        }
        if(sum%6!=2&&sum%6!=4&&sum!=1)
        {
            f=1;
        }
        if(f==1)
        {
            printf("No\n");
        }
        else
        {
            printf("Yes\n");
        }
    }
    return 0;
}



1010 Triangulation

空间博弈,Dawson’s Kayles 问题,表示完全不知道,百度一下后也发现只有一篇外语论文有提到。

有兴趣的可以去玩一下这个:传送门

标程上打的表也看不懂,最后还是自己写的sg函数,由于标程上说了循环节是34,所以就开了1000的数组。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
inline void RD(int &ret)
{
    char c;
    do
    {
        c=getchar();
    }
    while(c<'0'||c>'9');
    ret=c-'0';
    while((c=getchar())>='0'&&c<='9')
    {
        ret=ret*10+(c-'0');
    }
}
inline void OT(int a)
{
    if(a>=10)
    {
        OT(a/10);
    }
    putchar(a%10+'0');
}
int sg[1005];
bool t[1005];
void f()
{
    int i,j;
    for(i=2;i<1000;++i)
    {
        fill(t,t+i-1,false);
        for(j=0;j<=i-2;++j)
        {
            t[sg[j]^sg[i-2-j]]=true;
        }
        for(j=0;;++j)
        {
            if(!t[j])
            {
                sg[i]=j;
                break;
            }
        }
    }
}
int main()
{
    f();
    int t,i,n,x,sum;
    RD(t);
    while(t--)
    {
        RD(n);
        sum=0;
        for(i=0;i<n;++i)
        {
            RD(x);
            if(x<=100)
            {
                sum^=sg[x];
            }
            else
            {
                sum^=sg[x%34+3*34];
            }
        }
        if(sum==0)
        {
            printf("Dave\n");
        }
        else
        {
            printf("Carol\n");
        }
    }
    return 0;
}


1011 Unshuffle

最坑的题啊,题意很好理解,还是special judge,但最后也没发现这居然是一道2-sat。。。建完图,最后一个简单的dfs就搞定了。。。无语啊

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
inline void RD(int &ret)
{
    char c;
    do
    {
        c=getchar();
    }
    while(c<'0'||c>'9');
    ret=c-'0';
    while((c=getchar())>='0'&&c<='9')
    {
        ret=ret*10+(c-'0');
    }
}
inline void OT(int a)
{
    if(a>=10)
    {
        OT(a/10);
    }
    putchar(a%10+'0');
}
int a[2001],v[2001],n;
bool dfs(int x,int y)
{
    int i,j,f=0;
    if(x>=n-2)
    {
        return 1;
    }
    for(i=x;i<n-1;++i)
    {
        if(v[i]==0)
        {
            v[i]=-1;
            for(j=y;j<n;++j)
            {
                if(a[i]==a[j]&&v[j]==0)
                {
                    v[j]=1;
                    if(dfs(i+1,j+1)==1)
                    {
                        return 1;
                    }
                    v[j]=0;
                }
            }
            f=1;
            v[i]=0;
            break;
        }
    }
    if(f==0)
    {
        return 1;
    }
    return 0;
}
int main()
{
    int t,i;
    RD(t);
    while(t--)
    {
        memset(v,0,sizeof(v));
        RD(n);
        for(i=0;i<n;++i)
        {
            RD(a[i]);
        }
        dfs(0,1);
        for(i=0;i<n;++i)
        {
            if(v[i]==-1)
            {
               OT(0);
            }
            else if(v[i]==1)
            {
                OT(1);
            }
        }
        printf("\n");
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值