這題證明俺現在真是老了,退步了,這是第一份代碼:
-
#include <fstream>
-
using namespace std;
-
-
ifstream fin("kimbits.in");
-
ofstream fout("kimbits.out");
-
-
unsigned int N, L, pos;
-
-
int main()
-
{
-
fin >> N >> L >> pos;
-
-
unsigned int num = 0, count = 0, max = (1<<N)-1, bit1, tmp;
-
while(count < pos)
-
{
-
if(num > max) break;
-
bit1 = 0, tmp = num;
-
for(; tmp > 0; bit1++)
-
tmp &= (tmp - 1);
-
if(bit1 <= L) ++count;
-
++num;
-
}
-
-
num -- ;
-
for (int i = N-1; i >=0; --i)
-
fout << ((num >>i) & 0x1u);
-
fout << endl;
-
return 0;
-
}
其實還是挺簡潔的哈,就是會超時,因爲基本思路是暴力搜索。
這個是很鬱悶的,看數據,確實太大了。仔細端詳一番,覺得有DP的感覺,例如,對於(二進制)二位數:10 11,要得到三位數,實際上就是移位和移位+1,+1的操作中可以判斷+1後得到的數字中的1是不是超過了給定的L,不過,首先還是先崩潰了一下:
-
#include <fstream>
-
#include <deque>
-
#include <vector>
-
using namespace std;
-
-
ifstream fin("kimbits.in");
-
ofstream fout("kimbits.out");
-
-
typedef unsigned int UINT;
-
UINT N, L, pos;
-
vector<deque<UINT> > dp;
-
-
inline int printBinary(UINT num)
-
{
-
for (int i = N-1; i >=0; --i)
-
fout << ((num >>i) & 0x1u);
-
fout << endl;
-
return 0;
-
}
-
-
int main()
-
{
-
fin >> N >> L >> pos;
-
-
if(pos <= 2) {
-
printBinary(pos-1);
-
return 0;
-
}
-
-
deque<UINT> d, dPre;
-
d.push_back(0);
-
for(UINT i = 0; i <= N; ++i)
-
dp.push_back(d);
-
-
dp[0][0] = 1, dp[0].push_back(1);
-
UINT count = 2, uTmp;
-
-
for(UINT i = 0; i < N; ++i)
-
{
-
for(UINT k = 0; k <= i; ++k)
-
{
-
d.clear();
-
for(UINT j = 1; j <= dp[k][0]; ++j)
-
{
-
uTmp = (dp[k][j] << 1);
-
if(++count == pos) return printBinary(uTmp);
-
-
if(k+2 <= L) // k從0開始的
-
{
-
uTmp = (dp[k][j]<<1)+1;
-
if(++count == pos) return printBinary(uTmp);
-
d.push_back(uTmp);
-
}
-
-
dp[k][j] <<= 1;
-
}
-
if(k == i)
-
{
-
dp[k+1].insert(++dp[k+1].begin(), d.begin(), d.end());
-
dp[k+1][0] += d.size();
-
}
-
if(k > 0)
-
{
-
dp[k].insert(++dp[k].begin(), dPre.begin(), dPre.end());
-
dp[k][0] += dPre.size();
-
}
-
dPre = d;
-
}
-
}
-
-
return 0;
-
}
時間還不知道,空間先扛不住了:
看Test 6和7,估計這個辦法也不咋滴,爲什麼呢,究其原因還是無效計算過多。下面是AC的代碼,主要算法思想寫在註釋裏了,這道題本來很簡單的,卻搞了我這麼久,受打擊了,嗚嗚....
-
#include <fstream>
-
using namespace std;
-
typedef unsigned int UINT;
-
ifstream fin("kimbits.in");
-
ofstream fout("kimbits.out");
-
-
UINT N, L, pos;
-
UINT dp[33][33]; // dp(i,j)表示長度爲i,1的個數不超過j的串有多少
-
int res[33]={0};
-
-
int main()
-
{
-
fin>> N >> L >> pos;
-
for(UINT j = 0; j <= L; j++)
-
dp[0][j] = 1;
-
-
// 方程:f[j,k]=f[j-1,k]+f[j-1,k-1]; 分別表示在當前位加上0和加上1時的兩種狀況
-
// 邊界:f[j,0]=1, f[0,j]=1, f[j,k](k>j)=f[j,j]
-
// 這樣我們得到了所有的f[j,k] 需要做的就是據此構造出所求字符串
-
for(UINT i = 0; i <= N; i++)
-
{
-
for(UINT j = 0; j <=L; j++)
-
{
-
if(j == 0) dp[i][j] = 1;
-
else if(j <= i) dp[i][j] = dp[i-1][j] + dp[i-1][j-1];
-
else if(j > i) dp[i][j] = dp[i][i];
-
}
-
}
-
-
// 構造思路如下:
-
// 設所求串爲S,假設S的位中最高位的1在K位
-
// 那麼必然滿足:
-
// F[K-1,L]<pos and F[K,L]>=pos
-
// 這樣的K是唯一的, 所以S的第一個1在從右至左第K位
-
// 因爲有F[K-1,L]個串第K位上爲0,所以所求的第I個數的後K位就應該是:
-
// 滿足"位數爲K且串中1不超過L-1個"這個條件的第 pos - F[K,L] 個數 => 遞歸的過程
-
while(pos > 1)
-
{
-
for(int i = N-1; i>=0; i--)
-
{
-
if(dp[i][L] < pos)
-
{
-
res[N-i] = 1;
-
pos -= dp[i][L];
-
break;
-
}
-
}
-
L--;
-
}
-
UINT i = 1;
-
while(res[i] == 0 && 33 - i <= N) i++;
-
if(i == N+1) i = 1;
-
for(; i <= N; i++)
-
fout << res[i];
-
fout << endl;
-
return 0;
-
}