POJ 3187 Backward Digit Sums

题意:

我们把1-n这n个数的某个排列摆成一排,然后相邻两个数的和放到下一行,依此类推,形成一个三角形

3   1    2   4

   4   3   6

     7   9

      16

给你n和最终得到的和k,求第一行的系列(字典序最小)

我们可以发现每个数字的计算次数是一个杨辉三角

             1   1

          1    2    1

       1    3     3    1

   1     4     6      4     1

              ......

所以我们只要枚举1-n的全排列,计算sum{ans[i]*c(i-1,n-1)}是否为K就行了

当然从顶层一步一步算到最低也是一样的

10!为380W,而且因为左右对称,规模能减一半

枚举全排序能用STL中的next_permutation能很方便的求出

如果不知道这个函数,就写个DFS

 //#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<sstream>
#include<cmath>
#include<climits>
#include<string>
#include<map>
#include<queue>
#include<vector>
#include<stack>
#include<set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define pb(a) push_back(a)
#define INF 0x1f1f1f1f
#define lson idx<<1,l,mid
#define rson idx<<1|1,mid+1,r
#define PI  3.1415926535898
void debug()
{
#ifdef ONLINE_JUDGE
#else
    freopen("d:\in.txt","r",stdin);
   // freopen("d:\out1.txt","w",stdout);
#endif
}
char getch()
{
    char ch;
    while((ch=getchar())!=EOF)
    {
        if(ch!=' '&&ch!='
')return ch;
    }
    return EOF;
}

int cc(int m,int n)

{
    int k=1;
    for(int i=0;i<n;i++)
        k*=(m-i);
    for(int i=1;i<=n;i++)
        k/=i;
    return k;

}
int c[11][11];
int n,k;
int ans[11];
int main()
{
    for(int i=1;i<=10;i++)    //预处理出全部C(n,i),只是在追求速度,可以不必
        for(int j=0;j<=i;j++)
            c[i][j]=cc(i,j);
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        for(int i=1;i<=n;i++)ans[i]=i;
        do
        {
            int sum=0;
            for(int i=1;i<=n;i++)
                sum+=ans[i]*c[n-1][i-1];
            if(sum==k)break;
        }while(next_permutation(ans+1,ans+1+n));
        for(int i=1;i<=n;i++)
            printf("%d%c",ans[i],i==n?'
':' ');
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/BMan/p/3238267.html