地址:click here
国防科大今年校赛的I题目,大意是:对于正整数N、K,N可以表示成若干个质数之和的形式,问合法的方案数有多少(质数相同次序不同视为同一方案),并输出字典序第K大的表示方案。
我第一反应是用DFS去做,并且思路比较清晰敲好代码了。一开始好傻还保存全部状态后来觉得不对,方案太多会溢出,就不保存,每次都更新直到更新到解才停止。当时没有正确估计方案数全部保存下来一直WA,回来改了后通过了全部的测试数据,但是妥妥的TLE。
此题其实是一个DP问题,dp[i][j]是正整数i的分解其中第一个质数j的方案数,递推公式就是dp[i][j] = sum(dp[i-j][k] , 2=<k<=min(i-j, j)),(因为2是素数第一个),一开始预处理从0到200,大概O(N^3)的复杂度,然后输入一个N和K,方案数就是sum(dp[N][k], 2=<k<=N)
关键是求后面一个通过给出的K逆推,因为每一项的DP值都是知道的,要大的排在前面,所以从后面往前加求SUM,直到SUM>K了,就找到第一项了,然后记录这一项,用递归,下一个n是n-i下一个k就是k-sum+dp[n][i],需要注意的是,从后面往前面找的时候,前面的边界就是2,但是后面的边界却是前面记录的那一项,因为分解的时候前面必须要大于等于后面的项。然后直到K==0就找到了。其实N==0和K==0是同时达到的。就是这样
AC代码
#include<cstdio> #include<ctype.h> #include<algorithm> #include<iostream> #include<cstring> #include<vector> using namespace std; int dp[201][201],mark[201],path[105];//定义全局变量的时候千万不要在其他函数再次定义,不然全局变量不会改变,不要嘲笑我。。就是犯了这个错误所以记录下 int nct; void pprime() { int i,j; dp[2][2] = 1; for(i = 2; i < 15; i++) for(j = 2; i*j < 201; j++) mark[j*i] = 1; for(i = 2; i < 201; i++) if(mark[i] == 0) dp[i][i] = 1; } int min(int a,int b) { return a>b?b:a; } void init() { int i,j,k,sum; for(i = 2; i <= 200; i++) { for(j = 2; j <= i; j++) { if(mark[j] != 1 && i != j) { sum = 0; for(k = 2; k <= min(j,i-j); k++) sum+=dp[i-j][k]; dp[i][j] = sum; } } } } void find_path(int n,int k,int w) { int i; if(n == 0 || k ==0) return; int sum = 0; for(i = w; i >= 2; i--) { if(dp[n][i] != 0) sum+=dp[n][i]; if(sum >= k) { path[nct++] = i; break; } } find_path(n-i,k-sum+dp[n][i],i); } int main() { // freopen("input.txt","r",stdin); // freopen("out.in","w",stdout); pprime(); init(); int n,k,i; while(~scanf("%d%d",&n,&k)) { nct = 0; int ans = 0; for(i = 0; i <= 200; i++) ans+=dp[n][i]; if(k > ans) k = ans; printf("%d\n%d=",ans,n); find_path(n,k,200); for(i = 0; i < nct; i++) { printf("%d",path[i]); if(i != nct-1) printf("+"); } printf("\n"); } return 0; } /************************************************************** Problem: 1425 User: HNU_TEAM_3 Language: C++ Result: Accepted Time:0 ms Memory:1644 kb ****************************************************************/
原文地址:http://blog.csdn.net/glqac/article/details/24675631