标签:思想 精度 problem 内存 flag net 优化 个数 文件
题目链接:https://www.luogu.org/problem/P1771
想要更多磨练的,这里https://gmoj.net/senior/#main/show/1344
区别在内存空间的限制上。
首先,观察这道题。
观察结束。
实现:组合数学(递推),快速幂,高精加。
公式:C(k,x^x%1000)
递推式应该比较容易想到:假设目前要分解 n ,把它分解成 m 份。现在先把 n 分成 1 和 n-1,答案加上:(分解 n-1 时的分法数)*(分解1时的分法数)。然后把 n 分成 2 和 n-2,答案加上(分解 n-2 时的分法数)* (分解2时的分法数)以此类推。注意这里分解成n-1和1与分解成n-2和2是两种情况,都要加上。其实应该就是隔板法的思想。
到了实现的步骤。首先要用快速幂处理 x 得到要分解的数 n ,然后递推:把1分成1份,把2分成1、2份,把3分成1、2、3份分别是多少种分法,用高精存起来。具体用dt[i][j]表示把i分成j份能有几种分法。顺带一提,杨辉三角拿邻接矩阵存起来,第i行第j个数就是把i分解成j份的分法,因为杨辉三角也有递推的性质。
这里放两个版本的代码,第一个方便理解一些;第二个加上了高精,还算了一下:要是用邻接矩阵会有8万多kb,因为纪中OJ这道题的空间限制 65536KB (不像洛谷给了125兆),所以加上了滚动数组。(当然65536KB的空间只能卡掉邻接矩阵,闲的没事用邻接表、压位高精之类也是可以的w)
附代码:
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #define ll long long using namespace std; ll x; int n,k,maxn; ll dt[1100][110];//把i分成j组的情况数 (杨辉三角 int ksm(int a,ll b,int mo) { int ret=1; while(b) { if(b&1)ret=ret*a%mo; a=a*a%mo; b>>=1; } return ret; } int main(){ cin>>k>>x; int n=x%1000;//求n的x次方%1000 n=ksm(n,x,1000);//求n分成k组的组合数 (n<=1000) for(int i=1;i<=n;i++) { dt[i][1]=1; if(i<=k) dt[i][i]=1; } for(int i=3;i<=n;i++)//画个杨辉三角就知道为什么从3开始。。 { for(int j=2;j<=i&&j<=k;j++)//将i分成j组 { dt[i][j]=dt[i-1][j-1]+dt[i-1][j]; } } cout<<dt[n][k]; }
和:
#include<iostream> #include<algorithm> #include<cstring> #define Lovelive long long using namespace std; Lovelive x; int n,k,maxn; char dt[2][101][400]; int al[400],bl[400],cl[400]; int first; int ksm(int a,Lovelive b,int mo) { int ret=1; while(b) { if(b&1)ret=ret*a%mo; a=a*a%mo; b>>=1; } return ret; } int main(){ cin>>k>>x; int xx=x%1000;//求xx的x次方%1000 n=ksm(xx,x,1000);//求n分成k组的组合数 (n<=1000) dt[0][1][0]=‘1‘; dt[0][2][0]=‘1‘; for(int i=3;i<=n;i++) { for(int j=2;j<i&&j<=k;j++)//将i分成j组 { dt[1-first][1][0]=‘1‘;//以下是高精操作 ,大意是把两个大数加起来(废话 memset(al,0,sizeof(al)); memset(bl,0,sizeof(bl)); memset(cl,0,sizeof(cl)); //dt[i-1][j-1],dt[i-1][j]; int lena=strlen(dt[first][j-1]); int lenb=strlen(dt[first][j]); for(int l=1;l<=lena;l++) al[l]=dt[first][j-1][lena-l]-‘0‘; for(int l=1;l<=lenb;l++) bl[l]=dt[first][j][lenb-l]-‘0‘; int lenc=1,yu=0; while(lenc<=lena||lenc<=lenb) { cl[lenc]=al[lenc]+bl[lenc]+yu; yu=cl[lenc]/10; cl[lenc]%=10; lenc++; } cl[lenc]+=yu; if(cl[lenc]==0)lenc--; int flag=0; while(lenc) { dt[1-first][j][flag]=cl[lenc]+‘0‘; lenc--; flag++; } } first=1-first; if(i<=k) dt[first][i][0]=‘1‘; } cout<<dt[first][k]; }
补充纪中OJ上的得分情况:20分是乱搞到的,40分是有策略无高精,60与AC的差距在有没有优化空间
标签:思想 精度 problem 内存 flag net 优化 个数 文件
原文地址:https://www.cnblogs.com/snowysniper/p/11402777.html