codeforces 552C数制的转换,算是状态压缩吧

来源:互联网 发布:哈工大大数据集团简介 编辑:程序博客网 时间:2024/05/21 05:21

由于数据量实在太大,这个题没法用普通的枚举方式进行计算。

其实题目就想是()+()+()=m+()+()+()满足这个东西罢了。

那么我们可以简化一下,也就是要满足(  ()+()+()  )-(  ()+()+()  )=m,把大括号里的数看成一个数,那么就成了()-()=m这个东西了。

那么我们来一下状态压缩。把这两个数想做两个有位置的w进制的串。

我们最终要凑出m,为了方便,也为了对应上面的串,我们把m转换成w进制的数,分别对应到串的相应的位置。

    口口口口口口口口

-   口口口口口口口口

------------------------------

                   口口口口 

下面的框就是你转换w进制成的数。

这就相当于w进制的两个数相减罢了。

//从右往左每个框的权值分别是w^0,w^1,w^2,w^3………………

然后我们要凑出m(转换成w进制的m)。

要凑出m,我们转换一个思路。

这里每一列只有三种选择,要么上1下0,要么上0下0,要么上0下1(这个时候需要借位),不可能上1下1,也不可能上2下0或者上0下2(因为你每种砝码只有一个,就是说这一列总和只能是1或者0)。

那么你想这三种组合能搞出什么数呢?

注意啊~~~      结果中的数都是w进制的数啦~

上0下0,能在结果那一栏出来0。

上1下0能在结果那一栏出现1。

上0下1,能出现w-1(要向前借一位)。//这个没问题能理解吧?比如十进制的10-1,最后一位向前一位借1,最后一位的结果上就是9(进制数-1)。

全0或者上1下0好处理,那么我们处理一下借位。其实借位就是在它的前一位+1就可以了。你把前一位+1了之后,前一位可能超过了进制,那么就要向前进一位。

(这里我也不明白为什么,可能以后更新吧)


也就是你转换出来的每一位上转化后(注意这个转化后不是你直接转化出来的裸数)的数,只能是三个数,要么是0,要么是1,要么是w-1,只有这三个数才能被凑出来,如果出现了一个不是这个的,最终结果就是不能凑出来。


其实这个T有个很致命的洞。但是还要数据没有出那么坑的。


我说的不是很清楚,希望大家能多花时间自己理解一下这些脑洞题。也是写了这个留个脚印。

AC代码

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <algorithm>#include <map>using namespace std;const int maxn=1e4+10;const int inf=0x3f3f3f3f;int sta[maxn];int main(){    //脑洞打开……    int w,m;    while(scanf("%d%d",&w,&m)==2)    {       memset(sta,0,sizeof(sta));       int cnt=0;       //先把数转换成w进制的数,注意是倒着存的。       while(m)       {           sta[cnt++]=m%w;           m/=w;       }       cnt--;       bool f=1;       for(int i=0;i<=cnt;i++)       {           if(sta[i]>=w)//处理超进制的数           {               sta[i+1]++;               sta[i]%=w;           }           if(sta[i]<=1) continue;//结果是0或者1都可以           else if(sta[i]==w-1)//这个是需要借位的情况。           {               sta[i+1]++;           }           else//如果以上情况都没有,那就凑不出来           {               f=0;break;           }       }        f?printf("YES"):printf("NO");        printf("\n");    }}



原创粉丝点击