我的第一篇随笔 P1118 [USACO06FEB]Backward Digit Sums G/S 题解
P1118 [USACO06FEB]Backward Digit Sums G/S 题解
一.题意
给出一个数n和一个目标值target,target是某序列按照杨辉三角方式叠加的数的最后一行(也可以说是第一行),求这个序列(要求字典序最小奥)。
二.切入点
1.怎么暴力?可以用next_permutation(老懒人了),复杂度是O(12!),12!= 4.7e8,本题的时限是1s,最多也就1e8,显然过不了,所以需要剪枝。
2.怎么剪枝?首先需要明白这个总和是怎么算的,根据叠加方式,那应该是杨辉三角的第n列系数。有了计算总和的办法,就可以使用比较常见的剪枝策略,当目标累加值大于target就给它剪掉,肥肠好用哟ovo/****
三.实现过程中的难点
我相信,在想出预处理杨辉三角系数后,这道题应该也难不住大家了。不过作为蒟蒻,实际上调得蛮久的,因为蒟蒻的debug能力还不够厉害嘛,以后不要删掉测试输出了,不然要打好多遍,代码高效性远大于代码美观程度,当然是这样的,也算给本蒟蒻一个教训。
最后,谢谢阅读,奉上本蒟蒻的代码:\ qaq /完美收场
#include#define rep(i,x,n) for(int i=x;i<=n;i++) using namespace std; int s[20][20];//系数 int st[20];//判断dfs时数有没有被枚举过 int d[20];//数字 vector q; int n,target; void init(int n=12) { rep(i,1,n) d[i]=i;//初始化数组 s[1][1]=1; rep(i,2,n) rep(j,1,n) s[i][j]=s[i-1][j-1]+s[i-1][j];//初始化杨辉三角系数 } void dfs(int x,int sum) { if(sum>target) return; if(x==n&&sum==target) { for(auto i:q) cout << i << ' '; exit(0); } rep(i,1,n) { if(!st[i]) { st[i]=1; q.push_back(i); dfs(x+1,i*s[n][x+1]+sum); q.pop_back(); st[i]=0; } } } int main() { init();//预处理出系数 cin >> n >> target; dfs(0,0); return 0; }