Topcoder SRM523-527(DIV2)

SRM 523

现在有3种类型的积木,尺寸分别为1*1*1,1*1*2,1*1*3.如图所示.
这里写图片描述

现在给定一个1*1*w的底座和作品最高的高度,Lay博士可以在底座上搭积木完成作品,但是必须满足以下条件.积木必须放置在整数位置,且当一个积木能放在第i层,必须保证它的两个端点必须放置在已有积木之上.一个作品的高度就是积木的层数(除底座之外).两个作品视作不相同有两种情况:作品a的某一个位置有积木,b的相同位置没有;或a,b的某个位置都有积木,但是是不同类型的积木.
这里写图片描述

给出w,h,求出一共有多少种不同的方案.答案对1e9+7取模.

1≤w,h≤10.

下图是w=3,h=2的例子.
这里写图片描述

思路:

<1>本题的w<=10所以可以所以用二进制压缩状态
<2>先计算出对于同一种状态的积木有多少种不同的组成方式
<3>状态的转移dp[i][x1]+=dp[i-1][x2]*F[x1][x2];(对于一层状态为x2 的积木有N个方法使其转移成x1)

        //对于一层积木例如11101101;它的组成的可能为sum[3]*sum[2]*sum[1];
        //通过递推很容易得到
        sum[0]=sum[1]=1;sum[2]=2;sum[3]=4;
        for(int i=4;i<=10;i++)sum[i]=sum[i-1]+sum[i-2]+sum[i-3];
        //预处理F
        for(int i=1;i<1<<W;i++)for(int j=1;j<1<<W;j++){
            while(x1||x2)a[++num]=x1%2,b[num]=x2%2,x1/=2,x2/=2;
            //如果a[i]有而b[i]没有只有一种情况合法即
            //11111
            //10111
            //于是这个111就确定了F[11111][10111]=F[00011][10111]*1;
            for(int c=1;c<=W;c++)if(a[c]&&!b[c]){
                if(a[c+1]&&a[c-1]&&b[c-1]&&b[c+1])a[c]=a[c+1]=a[c-1]=0;
                else ok=0;
            }if(ok){
                F[i][j]=1;cnt=0;
                for(int c=1;c<=W+2;c++){
                    if(a[c])cnt++;
                    else F[i][j]*=sum[cnt],cnt=0;
                }
            }
        }
    for(int i=1;i<1<<W;i++)
        dp[1][i]=val[i];
    for(int i=1;i<H;i++)
    for(int x=1;x<1<<W;x++)
    for(int y=1;y<1<<W;y++)
        dp[i+1][x]=(dp[i+1][x]+dp[i][y]*F[x][y])%P;
    for(int i=1;i<=H;i++)
    for(int x=1;x<1<<W;x++)
        ans=(ans+dp[i][x])%P;
    return ans;
}

SRM 524

你的任务是找到一个最小的正整数x,使得:

x是N的倍数。
x的十进制表示中不存在被禁用的数字。
现在告诉你哪些数字被禁用。

如果无解,返回一个字符串”IMPOSSIBLE”。

如果解位数小于9,直接返回表示该数的字符串。

否则,你只需要给出一个省略形式的解,形式如”abc…def(g digits)”,其中abc表示该数开头的三个数字,def表示该数结尾的三个数字,g表示这个数字的位数。
(N<=10000)

思路:

<1>使用BFS从小到大枚举所以的数
<2>很容易发现对于一个数A其有贡献的值即为B=A % N 所以已经出现过的B就无需记录了
<3>(A*10+K)%N==(B*10+k)%N;

struct node{
    //a表前3位,b表最后的3位
    short a,b,len,res;
    int p//原数;
    node(){a=0,b=0,len=0,res=0,p=0;}
    void pt(){
        if(len<=8)printf("%d",p);
        else printf("%d+"..."+%d+"("+%d+" digits)",a,b,len);
    }   
};
    for(int i=0;i<x.size();i++)mark[x[i]]=1;
    for(int i=0;i<10;i++)if(!mark[i])c[num++]=i;
    node tmp;tmp.len=1;
    for(int i=0;i<num;i++)
        if(c[i]){
        tmp.p=tmp.b=c[i];
        tmp.res=c[i]%n;
        Q.push(tmp);
    }node nx,nw;
    int l,r,b,ok=0;
    while(!Q.empty()){
        nw=Q.front();Q.pop();
        if(nw.res==0){
            nw.pt();return 0;
        }nw.len++;
        if(nw.len<=8)ok=1;
        if(nw.a<=99)nw.a=nw.a*10+nw.b/100;
        nx=nw;
        b=nw.b*10%1000;
        r=nw.res*10;
        for(int i=0;i<num;i++){
            nx=nw;
            nx.res=(r+c[i])%n;
            nx.b=b+c[i];
            if(ok)nx.p=nx.p*10+c[i];
            if(hav[nx.res])continue;
            hav[nx.res]=1;
            Q.push(nx);
        }
    }puts("IMPOSSIBLE");
}

SRM 525

现在有一个3*3的矩形,和两行关于矩形的信息rowStrings和columnStrings:
•0<=i<=2,S[i][0]+S[i][1]+S[i][2]= rowStrings[i].
•0<=i<=2,S[0][i]+S[1][i]+S[2][i]= columnStrings[i];
例如下述矩形的rowStrings[]={“123”,456”,789”}; columnStrings[]={“147”,”258”,”369”};
这里写图片描述

现给出rowStrings和columnStrings,询问满足条件的矩形个数;
0<= rowStrings和columnStrings内字符串的长度 <=50;

思路:

<1>由于本题的数据小可以直接枚举其中几个格子中的元素的个数
<2>显然只需要枚举其中4个即可

int main(){
        if(A[0].S+A[1].S+A[2].S!=B[0].S+B[1].S+B[2].S)return 0;
        long long ans=0;
        for(int x1=0;x1<=A[0].S;x1++)
        for(int x2=0;x2<=A[0].S-x1;x2++)
        for(int x4=0;x4<=A[1].S;x4++)
        for(int x5=0;x5<=A[1].S-x4;x5++){
            int x7=B[0].S-x1-x4,x8=B[1].S-x5-x2;
            if(B[0].substr(0,x1)+B[1].substr(0,x2)+B[2].substr(0,A[0].S-x1-x2)!=A[0])continue;
            if(B[0].substr(x1,x4)+B[1].substr(x2,x5)+B[2].substr(A[0].S-x1-x2,A[1].S-x4-x5)!=A[1])continue;
            if(B[0].substr(x4+x1,x7)+B[1].substr(x5+x2,x8)+B[2].substr(A[1].S-x4-x5+A[0].S-x1-x2,A[2].S-x7-x8)!=A[2])continue;
            ans++;
        }return ans;
    }

SRM 527

定义一个数的Luckiness值为该数字中4出现的个数与7出现的个数之差。
给定A,B,求A到B区间的数的Luckiness值之和。(1<=A,B<=2,000,000,000)

思路

<1>ans=val[B]-val[A-1];
<2>一位一位地枚举时注意判断这位数是否需要小于A的该位(即之前的即为均和A逐位相等)
<3>对于一个数只有几个信息是有用的

void dfs(int x,int a,int b,int f){
    if(!x)return abs(a-b);
    int mx=f?c[x]:9,ans=0; 
    for(int i=0;i<=mx;i++){
        if(i==4)ans+=dfs(x+1,a+1,b,f&&mx==i);
        if(i==7)ans+=dfs(x+1,a,b+1,f&&mx==i);
        ans+=dfs(x+1,a,b,f&&mx==i);
    }
}
int main(){
    while(A)c[++num]=A%10,A/=10;
    ans=dfs(num,0,0,1);
}

SRM 527

现在有n种面值的零钱,对于0~n-1中的每个i,有一个面值为2^i的硬币.现在给出整数n,sum,cnt.你的任务找出一种硬币组合的方案使得硬币个数为cnt,硬币面值总和为sum.请输出每个面值硬币的数量.若有多种方案,输出字典序最小的.

1≤n≤60,1≤sum,cnt≤10^18

    vector<long long>res(n);//定义vector的[0,n-1]
        ll use=0;
        for(int i=0;i<n;i++){
            if(sum&1){res[i]=1;use++;}
            else res[i]=0;
            sum>>=1;if(!sum)break;
        }
        if(sum>0)use+=sum*2,res[n-1]+=sum*2;
        if(use>cnt)res.clear();
        ll res=cnt-use;
        for(int i=n-1;i>0&&res;i--){
            ll b=min(a,res[i]);        
            res[i]-=b;
            res[i-1]+=b*2;
            res-=b;
        }return res;
    }
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值