zoukankan      html  css  js  c++  java
  • [P1329] 数列

    设F[i,j]为长度为i是,前缀和为j的方案数。

    【转移】
    F[i,j] => F[i+1,j+i]
    F[i,j] => F[i+1,j-i]
    【原理】
    由于A[0]=0,所以有A[1]=-1或A[1]=1 。又要满足|A[i]-A[i-1]|=1,所以 这样思考:
    从F[i,]转移到F[i+1,]时,假象在长度为i的A序列后添一个A[i]+1 或A[i]-1。我们惊奇地发现,这样是做不出来的。

    怎么办呢???

    看过题解后我们发现,上述方法不适用的原因是A[n]情况太多了。不方便。 与之相反的是,A[0]={0},A[1]={1,-1}的情况就很少 。我们何不在A[0]和A[1]中插入一个数构成新序列呢 ??

    举个栗子:当A[1]为1时,在其中插入一个1,为了满足 |A[i]-A[i-1]|=1 的性质,不得不当原来的A[1~i]都加上一个1或-1,即转移到了F[i+1,j+i-1+1] 和 F[i+1,j-i+1-1] 。

    还有三种情况,道理相同就不再赘述了。

    【输出答案】搜索,利用F数组剪纸就好。
    我是真菜啊 。

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int N=110;
    const int M=20000;
    
    int n,sum,a[N];
    long long tot,f[N][M+1];
    
    void print(int x) {
    	if(x==1 && !sum) {
    		printf("0");
    		for(int k=0,i=n; i>1; --i) {
    			k+=a[i]; printf(" %d",k);
    		}
    		printf("
    ");
    		if(--tot==0) exit(0);
    	}
    	if(f[x][sum<0?sum+M:sum]==0) return;
    	a[x]=-1;
    	sum+=(x-1);
    	print(x-1);
    	sum-=(x-1);
    	a[x]= 1;
    	sum-=(x-1);
    	print(x-1);
    	sum+=(x-1);
    }
    
    int main() {
    	f[1][0]=1;
    	scanf("%d%d",&n,&sum);
    	for(int i=1,j,k; i<n; ++i) {
    		for(int s=-9999; s<=9999; ++s) {
    			j=s;
    			if(j<0) j+=M;
    			if(!f[i][j]) continue;
    			k=s+i;
    			if(k<0) k+=M;
    			f[i+1][k]+=f[i][j];
    			k=s-i;
    			if(k<0) k+=M;
    			f[i+1][k]+=f[i][j];
    		}
    	}
    	if(sum<0) tot=f[n][sum+M];
    	else tot=f[n][sum];
    	printf("%lld
    ",tot);
    	if(tot>100) tot=100; 
    	print(n);
    	return 0;
    }
    
  • 相关阅读:
    UITableView设置Cell左滑多个按钮(编辑,删除,置顶等)
    php处理ajax
    Vue实现增删改查功能
    Vue中slot内容分发
    两个Vue Demo
    js继承
    nodejs+express+mongodb搭建博客
    express中放置静态文件
    初始化一个Express项目
    mongodb使用1
  • 原文地址:https://www.cnblogs.com/nosta/p/10197940.html
Copyright © 2011-2022 走看看