2013 Multi-University Training Contest 7

11 篇文章 0 订阅
7 篇文章 0 订阅

1001 Hyperspace

求最远曼哈顿距离,求曼哈顿距离并不难,难的是这题需要求n次,而且其中有删点,k维空间。。。

虽然比赛时没有AC,但也想到了枚举2^k种情况+-得到最远曼哈顿距离的方法,可是由于没想到用stl里的set,multiset,map等处理删点问题,导致复杂度一直为O(n^2*k*2^k)

之后看了标程才知道了原来可以去掉n次。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<set>
#define mem(a,b) memset(a,b,sizeof(a))
#define INF 1e9
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[60001][10];
multiset<int>t[32];
multiset<int>::iterator it;
int main()
{
    int n,k,i,j,q,sum,op,x,t1,t2,ans;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        for(i=0; i<(1<<k); i++)
        {
            t[i].clear();
        }
        for(i=1; i<=n; i++)
        {
            RD(op);
            if(op==0)
            {
                for(j=0; j<k; j++)
                {
                    scanf("%d",&a[i][j]);
                }
                for(j=0; j<(1<<k); j++)
                {
                    sum=0;
                    for(q=0; q<k; q++)//就是这里,我本来是一个for(0-n),用二维数组保存,和用multiset查找,去重,删点
                    {
                        if(j&(1<<q))
                        {
                            sum+=a[i][q];
                        }
                        else
                        {
                            sum-=a[i][q];
                        }
                    }
                    t[j].insert(sum);
                }
            }
            else
            {
                RD(x);
                for(j=0; j<(1<<k); j++)
                {
                    sum=0;
                    for(q=0; q<k; q++)
                    {
                        if(j&(1<<q))
                        {
                            sum+=a[x][q];
                        }
                        else
                        {
                            sum-=a[x][q];
                        }
                    }
                    it=t[j].find(sum);
                    t[j].erase(it);
                }
            }
            ans=0;
            for(j=0; j<(1<<k); j++)//最后直接两两相减就成
            {
                it=t[j].end();
                it--;
                t1=(*it);
                it=t[j].begin();
                t2=(*it);
                ans=max(ans,t1-t2);
            }
            OT(ans);
            printf("\n");
        }
    }
    return 0;
}


1004 Mutiples on a circle

一道环形的DP题,卡时间卡得很紧,所以时间复杂度只能为O(n*k)

t[i][j]代表第i元素结尾,j为余数的种数。3倍延长环去计算。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#define mem(a,b) memset(a,b,sizeof(a))
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 f[50001],s[50001],e[150001],t[50001][201];
int main()
{
    int n,mod,l,w,sum,ans,num,i,j;
    while(scanf("%d%d",&n,&mod)!=EOF)
    {
        e[0]=1;
        memset(t,0,sizeof(int)*n*201);//注意初始化t时一定要这样写,不然会TLE到死。
        for(i=1; i<n*3; i++)
        {
            e[i]=e[i-1]*10%mod;
        }
        for(i=0; i<n; i++)
        {
            RD(f[i]);
            num=f[i];
            if(f[i]==0)
            {
                ans=1;
            }
            else{
            ans=0;
            while(num)
            {
                ans++;
                num/=10;
            }
            }
            s[i]=ans;
        }
        f[n]=f[0];
        s[n]=s[0];
        sum=0;
        l=0;
        w=0;
        for(i=n; i>0; i--)
        {
            sum=(sum+f[i]*e[l])%mod;
            l+=s[i];
            t[0][sum]++;
        }
        w+=t[0][0];
        for(i=1; i<n; i++)
        {
            for(j=0; j<mod; j++)
            {
                t[i][(j*e[s[i]]+f[i])%mod]+=t[i-1][j];//状态转移方程
            }
            sum=(sum*e[s[i]]+f[i])%mod;
            t[i][sum]--;
            t[i][f[i]%mod]++;
            sum=((sum-f[i]*e[l])%mod+mod)%mod;//sum-f[i]*e[l]有可能为负值且绝对值远小于mod,所以需要这样取余。
            w+=t[i][0];
        }
        OT(w);
        printf("\n");
    }
    return 0;
}


1006 Backup Plan

简单构造题。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#define mem(a,b) memset(a,b,sizeof(a))
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 n,m,i,j,k,a[105],w;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(i=0;i<n&&i<m;++i)
        {
            w=n-1;
            for(j=i;j<m;j+=n,w=(w-1+n)%n)
            {
                if(w==i)
                {
                    w=(w-1+n)%n;
                }
                a[j]=w;
            }
        }
        for(i=0;i<m;++i)
        {
            printf("%d %d",i%n+1,a[i]+1);
            for(j=0;j<n;++j)
            {
                if(j!=i%n&&j!=a[i])
                {
                    printf(" %d",j+1);
                }
            }
            printf("\n");
        }
    }
    return 0;
}

1007 Present Day, Present Time

神奇的博弈,涉及到dp的部分处理,当时比赛时一直在想这题,但一直没想法。看了solution后才了解,是很简单的一个思想。

由于回收站的使用次数是不受限制的,所以各个回收站的容量的组合代表的数就是能被一次性回收掉的石子数量,而由于Bi的数量最多只有100,回收站的个数最多也只有100,所以当一次性使用所有回收站且只使用一次,那一次性最多回收10000个石子。接下去要求的是各堆石子最多能拿几次拿光,如果有不能拿光就直接判输,得到的各堆数量就简化成了一个NIM博弈,直接异或一遍,然后就可以判输赢就行。这题还有一个地方需要注意就是当Ai大于10000时,由于要求的是最多取的次数,所以之后就是循环min(Bi)。。。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#define mem(a,b) memset(a,b,sizeof(a))
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[10005],a[100005],b;
int main()
{
    int n,m,i,j,ans,sum,f,w;
    char x[11],y[11];
    while(scanf("%d%d%s%s",&n,&m,x,y)!=EOF)
    {
        for(i=0; i<n; ++i)
        {
            RD(a[i]);
        }
        mem(sg,-1);
        sg[0]=0;
        ans=101;
        for(i=0; i<m; ++i)
        {
            RD(b);
            ans=min(ans,b);
            for(j=0; j+b<10001; ++j)//dp过程
            {
                if(sg[j]>=0)
                {
                    sg[j+b]=max(sg[j+b],sg[j]+1);//每次求最多取的次数
                }
            }
        }
        sum=0;
        f=0;
        for(i=0; i<n; ++i)
        {
            w=a[i];
            if(w<=10000)
            {
                if(sg[w]<0)
                {
                    f=1;
                }
                sum^=sg[w];
            }
            else
            {
                w=(w-10000+ans)%ans+10000-ans;//之后循环节就是ans
                if(sg[w]<0)
                {
                    f=1;
                }
                sum^=sg[w]+(a[i]-w)/ans;
            }
        }
        if(f==0&&sum!=0)
        {
            printf("%s\n",x);
        }
        else
        {
            printf("%s\n",y);
        }
    }
    return 0;
}

我们好水,这次收获也算大。。。


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值