USACO Stringsobits, 还是得搬出动态规划来

来源:互联网 发布:8月份上海房产成交数据 编辑:程序博客网 时间:2024/04/30 20:25

这题证明俺现在真是老了,退步了,这是第一份代码:

  1. #include <fstream>
  2. using namespace std;
  3.  
  4. ifstream fin("kimbits.in");
  5. ofstream fout("kimbits.out");
  6.  
  7. unsigned int N, L, pos;
  8.  
  9. int main()
  10. {
  11.     fin >> N >> L >> pos;
  12.  
  13.     unsigned int num = 0, count = 0, max = (1<<N)-1, bit1, tmp;
  14.     while(count < pos)
  15.     {
  16.         if(num > max) break;
  17.         bit1 = 0, tmp = num;
  18.         for(; tmp > 0; bit1++)
  19.             tmp &= (tmp - 1);
  20.         if(bit1 <= L) ++count;
  21.         ++num;
  22.     }
  23.  
  24.     num -- ;
  25.     for (int i = N-1; i >=0; --i)
  26.         fout << ((num >>i) & 0x1u);
  27.     fout << endl;
  28.     return 0;
  29. }

其实还是挺简洁的哈,就是会超时,因为基本思路是暴力搜索。


这个是很郁闷的,看数据,确实太大了。仔细端详一番,觉得有DP的感觉,例如,对于(二进制)二位数:10 11,要得到三位数,实际上就是移位和移位+1,+1的操作中可以判断+1后得到的数字中的1是不是超过了给定的L,不过,首先还是先崩溃了一下:

  1. #include <fstream>
  2. #include <deque>
  3. #include <vector>
  4. using namespace std;
  5.  
  6. ifstream fin("kimbits.in");
  7. ofstream fout("kimbits.out");
  8.  
  9. typedef unsigned int UINT;
  10. UINT N, L, pos;
  11. vector<deque<UINT> > dp;
  12.  
  13. inline int printBinary(UINT num)
  14. {
  15.     for (int i = N-1; i >=0; --i)
  16.         fout << ((num >>i) & 0x1u);
  17.     fout << endl;
  18.     return 0;
  19. }
  20.  
  21. int main()
  22. {
  23.     fin >> N >> L >> pos;
  24.  
  25.     if(pos <= 2) {
  26.         printBinary(pos-1);
  27.         return 0;
  28.     }
  29.  
  30.     deque<UINT> d, dPre;
  31.     d.push_back(0);
  32.     for(UINT i = 0; i <= N; ++i)
  33.         dp.push_back(d);
  34.  
  35.     dp[0][0] = 1,  dp[0].push_back(1);
  36.     UINT count = 2, uTmp;
  37.  
  38.     for(UINT i = 0; i < N; ++i)
  39.     {
  40.         for(UINT k = 0; k <= i; ++k)
  41.         {
  42.             d.clear();
  43.             for(UINT j = 1; j <= dp[k][0]; ++j)
  44.             {
  45.                 uTmp = (dp[k][j] << 1);
  46.                 if(++count == pos) return printBinary(uTmp);
  47.  
  48.                 if(k+2 <= L) // k从0开始的
  49.                 {
  50.                     uTmp = (dp[k][j]<<1)+1;
  51.                     if(++count == pos) return printBinary(uTmp);
  52.                     d.push_back(uTmp);
  53.                 }
  54.  
  55.                 dp[k][j] <<= 1;
  56.             }
  57.             if(== i)
  58.             {
  59.                 dp[k+1].insert(++dp[k+1].begin(), d.begin(), d.end());
  60.                 dp[k+1][0] += d.size();
  61.             }
  62.             if(> 0)
  63.             {
  64.                 dp[k].insert(++dp[k].begin(), dPre.begin(), dPre.end());
  65.                 dp[k][0] += dPre.size();
  66.             }
  67.             dPre = d;
  68.         }
  69.     }
  70.  
  71.     return 0;
  72. }

时间还不知道,空间先扛不住了:


看Test 6和7,估计这个办法也不咋滴,为什么呢,究其原因还是无效计算过多。下面是AC的代码,主要算法思想写在注释里了,这道题本来很简单的,却搞了我这么久,受打击了,呜呜....

  1. #include <fstream>
  2. using namespace std;
  3. typedef unsigned int UINT;
  4. ifstream fin("kimbits.in");
  5. ofstream fout("kimbits.out");
  6.  
  7. UINT N, L, pos;
  8. UINT dp[33][33]; // dp(i,j)表示长度为i,1的个数不超过j的串有多少
  9. int res[33]={0};
  10.  
  11. int main()
  12. {
  13.     fin>> N >> L >> pos;
  14.     for(UINT j = 0; j <= L; j++)
  15.         dp[0][j] = 1;
  16.    
  17.     // 方程:f[j,k]=f[j-1,k]+f[j-1,k-1]; 分别表示在当前位加上0和加上1时的两种状况
  18.     // 边界:f[j,0]=1, f[0,j]=1, f[j,k](k>j)=f[j,j]
  19.     // 这样我们得到了所有的f[j,k] 需要做的就是据此构造出所求字符串
  20.     for(UINT i = 0; i <= N; i++)
  21.     {
  22.         for(UINT j = 0; j <=L; j++)
  23.         {
  24.             if(== 0) dp[i][j] = 1;
  25.             else if(<= i) dp[i][j] = dp[i-1][j] + dp[i-1][j-1];
  26.             else if(> i) dp[i][j] = dp[i][i];
  27.         }
  28.     }
  29.    
  30.     // 构造思路如下:
  31.     // 设所求串为S,假设S的位中最高位的1在K位
  32.     // 那么必然满足:
  33.     // F[K-1,L]<pos and F[K,L]>=pos
  34.     // 这样的K是唯一的, 所以S的第一个1在从右至左第K位
  35.     // 因为有F[K-1,L]个串第K位上为0,所以所求的第I个数的后K位就应该是:
  36.     // 满足"位数为K且串中1不超过L-1个"这个条件的第 pos - F[K,L] 个数 => 递归的过程
  37.     while(pos > 1)
  38.     {
  39.         for(int i = N-1; i>=0; i--)
  40.         {
  41.             if(dp[i][L] < pos)
  42.             {
  43.                 res[N-i] = 1;
  44.                 pos -= dp[i][L];
  45.                 break;
  46.             }
  47.         }
  48.         L--;
  49.     }
  50.     UINT i = 1;
  51.     while(res[i] == 0 && 33 - i <= N) i++;
  52.     if(== N+1) i = 1;
  53.     for(; i <= N; i++)
  54.         fout << res[i];
  55.     fout << endl;
  56.     return 0;
  57. }



原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 电脑开机卡在logo界面 手机卡在开机画面怎么办 联想笔记本开机卡在lenovo界面 开机卡在正在启动windows iphone卡在开机界面 笔记本开机卡在欢迎界面 电脑开机一直卡在开机画面 电脑开机一直卡在欢迎界面 开机卡在主板界面 dell开机卡在logo 戴尔笔记本开机卡在logo界面 三星手机开机卡在开机画面 手机卡在开机界面 今晚3d开什么号 电脑开机打不开任何软件 电脑开机显示屏没反应 电脑开机一直显示正在启动 电脑开机屏幕没反应 电脑开机显示屏显示无信号 电脑开机后黑屏 电脑开机后不显示桌面 电脑开机后黑屏不显示桌面 电脑开机后打不开任何软件 电脑开机后一直显示正在启动 电视开机后屏幕不亮 电脑开机后蓝屏 电脑开机后显示屏没反应 电脑开机后显示屏显示无信号 海信电视开机后黑屏 开机后黑屏 开机后显示器没反应 笔记本电脑开机后黑屏 电脑待机后怎么开机 笔记本开机后黑屏只有鼠标 笔记本电脑开机后不显示桌面 电脑蓝屏后开机屏幕不亮 电脑开机后桌面没有任何图标 电脑开机后屏幕没反应 电脑关机后自动开机 开机后 ntldrismissing后如何开机