约制1:同是1或者同是0的数字其相对位置不变。
求最大最小可用贪心求解。
简化题目:若延迟为d,从左往右数第i个数字到达的时间范围可以记为[i,i+d],题目说是[i+1,i+d+1],不影响结果。
约制2(书上说的,实际解题我的代码没有用到,但这是对的):假若有n位数字,到达的时间是[1,n+d],我们可以修改为[1,n]不影响结果。
化为dp中的一个常见模型,两个序列,一次从左往右取dp[i][j]代表第一个序列去了i个,第二个序列取了j个时的最优解。
然而这个题目不是最优解,严格地说这个题目是递推,而不是动归。
/**==========================================
* This is a solution for ACM/ICPC problem
*
* @source:uva 1228 Integer Transmission
* @type: dp
* @author: wust_ysk
* @blog: http://blog.csdn.net/yskyskyer123
* @email: 2530094312@qq.com
*===========================================*/
#define REP(i,n) for(int i=0 ;i<(n) ;i++)
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int INF =0x3f3f3f3f;
const int maxn= 64 ;
int n,d,numZero,numOne;
unsigned long long k;
int kase=0;
vector<int >ve1;
vector<int >ve0;
struct A
{
int x;
int ind;
}a[maxn+3] ;
unsigned long long dp[maxn+3][maxn+3];
bool cmp1(A x,A y)
{
if(x.x==y.x) return x.ind<y.ind;
else if(x.x==0) return x.ind<=y.ind+d;
return x.ind+d<y.ind;
}
bool cmp2(A x,A y)
{
if(x.x==y.x) return x.ind<y.ind;
else if(x.x==0) return x.ind+d<y.ind;
return x.ind<=y.ind+d;
}
void getA()
{
ve0.clear();
ve1.clear();
numZero=numOne=0;
unsigned long long t=k;
for(int i=n-1;i>=0;i--)
{
a[i].x=t%2;
a[i].ind=i;
t/=2;
}
REP(i,n)
{
if(a[i].x) numOne++, ve1.push_back(i);
else numZero++, ve0.push_back(i);
}
}
void getmin()
{
sort(a,a+n,cmp1);
unsigned long long x=0;
REP(i,n)
{
x=2*x+a[i].x;
}
printf(" %llu",x);
}
void getmax()
{
sort(a,a+n,cmp2);
unsigned long long x=0;
REP(i,n)
{
x=2*x+a[i].x;
}
printf(" %llu\n",x);
}
bool can(int numz,int numo ,int now)
{
if(now==0)
{
if(numz==numZero) return false;
if(numo==numOne) return true;
return ve0[numz]<=ve1[numo]+d ;
}
if(now==1)
{
if(numo==numOne) return false;
if(numz==numZero) return true;
return ve1[numo]<=ve0[numz]+d ;
}
}
void work()
{
dp[0][0]=1;
for(int i=0;i<=numZero;i++)
{
for(int j=0;j<=numOne;j++)
{
if(!i&&!j) {dp[i][j]=1;continue;}
dp[i][j]=0;
if (i-1>=0&&can(i-1,j,0) ) dp[i][j]+=dp[i-1][j];
if (j-1>=0&&can(i,j-1,1) ) dp[i][j]+=dp[i][j-1];
}
}
printf(" %llu",dp[numZero][numOne]);
}
int main()
{
while(~scanf("%d",&n)&&n)
{
scanf("%d%llu",&d,&k);
printf("Case %d:",++kase);
getA();
work();
getmin();
getmax();
}
return 0;
}