题目:http://acm.hdu.edu.cn/showproblem.php?pid=2983
题意:将一个n位的数发送,每一位的发送时间为i,但是网络有延迟d,收到时顺序可能会变,求总共有多少种可能性,并且最小和最大分别是多少
最大和最小比较容易求,只需要贪心的将1和0前移或后移
求方案数时,1和1的位置互换了并不影响,所以只需要考虑0和1的相对位置
用dp[i][j]表示现在接收了i个0,j个1
如果下一个1可以放在下一个0后面,那么现在可以接收0,如果下一个0可以放在下一个1后面,则可以接收1
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include<vector> #include<queue> #include<stack> #include<map> #include<set> using namespace std; const int N=70; typedef unsigned long long ll; int cnt0,cnt1,p0[N],p1[N],n,d; ll k,dp[N][N]; vector<int> v[N]; void init() { cnt0=cnt1=0; for(int i=n-1;i>=0;i--) if (k>>i&1) p1[++cnt1]=-i; else p0[++cnt0]=-i; } ll solve() { memset(dp,0,sizeof(dp)); dp[0][0]=1; for(int i=0;i<=cnt0;i++) for(int j=0;j<=cnt1;j++) { if (i<cnt0&&(j==cnt1||p1[j+1]+d>=p0[i+1])) dp[i+1][j]+=dp[i][j]; if (j<cnt1&&(i==cnt0||p0[i+1]+d>=p1[j+1])) dp[i][j+1]+=dp[i][j]; } return dp[cnt0][cnt1]; } ll findmin() { for(int i=0;i<n;i++) v[i].clear(); for(int i=n-1;i>=0;i--) if (k>>i&1) v[max(0,i-d)].push_back(1); else v[i].push_back(0); ll ans=0; for(int i=n-1;i>=0;i--) { sort(v[i].begin(),v[i].end()); for(int j=0;j<v[i].size();j++) ans=ans*2+v[i][j]; } return ans; } bool cmp(ll x,ll y) { return x>y; } ll findmax() { for(int i=0;i<n;i++) v[i].clear(); for(int i=n-1;i>=0;i--) if (k>>i&1) v[i].push_back(1); else v[max(0,i-d)].push_back(0); ll ans=0; for(int i=n-1;i>=0;i--) { sort(v[i].begin(),v[i].end(),cmp); for(int j=0;j<v[i].size();j++) ans=ans*2+v[i][j]; } return ans; } int main() { ios::sync_with_stdio(false); int ca=0; while(cin>>n&&n) { cin>>d>>k; init(); ca++; cout<<"Case "<<ca<<": "<<solve()<<" "<<findmin()<<" "<<findmax()<<endl; } return 0; }