math解题报告

在Sak同学的热心帮助下,终于成功的搞清了0.0
手动@Sak
[建议先看程序后看我的文字。。]
由于维数包括 当前位数、原数每位之和、原数*d每位之和、 *d后的进位, 维数太多了存不下,又要判断是否计算过这样由四维组成的状态,只好用起了位运算。
f[i][j][k]表示 运算到第i位 s1剩j s2剩k下=时 的一个二进制数(二进制是为了判重用。)
place[]存放的是一个可以改变f[i][j][k]某一位上的数字(0变1,1还是1,巧妙地运用“|”[按位或])的二进制。将f[i][j][k] |= place[l]即可改变。
判断是否找过这四维组成的状态可以:
if(f[i][j][k] & place[l] == 1)说明是计算过的,这个想想就清楚啦!

整个过程就是最高位找起(最高位比较特殊不能为0嘛,在主程序搜,dfs内部就是找剩余位上的)dfs的第四维也就是每个for(int j = 0; j < 9; j++)是枚举*d后的进位j/more,至于为什么进位只有0~8也是因为最大9×9只有81嘛,只能进8啦。。

这个程序设计不得不说真心巧妙和高端,佩服的五体投地。
考试有这样清晰的思维很羡慕。
以下是代码(嘘!)

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int maxn=1e2+5,maxs=10*maxn;
const short place[]={1<<0,1<<1,1<<2,1<<3,1<<4,1<<5,1<<6,1<<7,1<<8,1<<9,1<<10};
int n,s1,s2,d;
int x[maxn];
short f[maxn][maxs][maxs];
int dfn_clock;
int flag;
void dfs(int pos,int rest1,int rest2,int more){
    if(flag) return;
    if(rest1<0||rest2<0||rest1>9*pos||rest2>9*pos||(f[pos][rest1][rest2]&place[more])) return;
    if(!pos){
        if(more){
            f[pos][rest1][rest2]|=place[more];
            return;
        }
        for(int i=n;i;--i) printf("%d",x[i]);
        puts("");
        flag=1;return;
    }
    for(int i=0;i<10;++i){
        x[pos]=i;
        for(int j=0;j<9;++j) if((i*d+j)/10==more) dfs(pos-1,rest1-i,rest2-(i*d+j)%10,j);
    }
    f[pos][rest1][rest2]|=place[more];
}
int main(){
    freopen("math.in","r",stdin);
    freopen("math.out","w",stdout);
    scanf("%d%d%d%d",&n,&s1,&s2,&d);
    for(int i=1;i<10;++i){
        x[n]=i;
        for(int j=0;j<9;++j) dfs(n-1,s1-i,s2-(i*d+j)/10-(i*d+j)%10,j);
    }
    if(!flag) puts("Cirno is too smart");
    return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值