【递推】wikioi 1509 拯救LongMM

题目链接:http://wikioi.com/problem/1509/

分析:

首先,根据题意可以推断出,对于任意一个状态,达到全0状态的途径只有一条

由此,写出n=5的全排列:

步数  状态      1的位置   
0   0 0 0 0 0        
1   1 0 0 0 0          1
2   1 1 0 0 0        2 1
3   0 1 0 0 0        2
4   0 1 1 0 0      3 2
5   1 1 1 0 0      3 2 1
6   1 0 1 0 0      3   1
7   0 0 1 0 0      3
8   0 0 1 1 0    4 3
9   1 0 1 1 0    4 3   1    16 8 2 
10  1 1 1 1 0    4 3 2 1    16 8 4 2
11  0 1 1 1 0    4 3 2      16 8 4 
12  0 1 0 1 0    4   2      16 4
13  1 1 0 1 0    4   2 1    16 4 2  
14  1 0 0 1 0    4     1    16 2
15  0 0 0 1 0    4          16 
16  0 0 0 1 1  5 4        
17  1 0 0 1 1  5 4     1
18  1 1 0 1 1  5 4   2 1
19  0 1 0 1 1  5 4   2
20  0 1 1 1 1  5 4 3 2
21  1 1 1 1 1  5 4 3 2 1
22  1 0 1 1 1  5 4 3   1
23  0 0 1 1 1  5 4 3
24  0 0 1 0 1  5   3
25  1 0 1 0 1  5   3   1
26  1 1 1 0 1  5   3 2 1
27  0 1 1 0 1  5   3 2
28  0 1 0 0 1  5     2
29  1 1 0 0 1  5     2 1     
30  1 0 0 0 1  5       1     
31  0 0 0 0 1  5             
然后,随意选取9,10,11,12等几行作分析。

可以发现,

设 第 i 个 1 的位置为f[i],

则步数=2^f[i]-2^f[i-1]+2^f[i-2]+...

当有偶数个0的时候,答案减去1。

由此可得递推式,出解。

ps:由于数据较大,要用高精,而且要压位。

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int c[3000]; int wei,len=1,n,cc[3000];
int re[3000],a[1010],aa[3100];
void cheng(int jk)
{
  wei=1;
  cc[wei]=1;
  for (int i=1;i<=jk;i++)
  {
  	memset(c,0,sizeof(c));
  	for (int j=1;j<=wei;j++)
  	 {
  	 	c[j]+=cc[j]*2;
  	 	c[j+1]+=c[j]/100000000;
  	 	c[j]%=100000000;
  	 }
  	 if (c[wei+1]!=0)
  	 {
  	 	wei++;
  	 	while (c[wei]>=100000000)
  	 	 {
  	 	 	wei++;
  	 	 	c[wei]+=c[wei-1]/100000000;
  	 	 	c[wei-1]%=100000000;
  	 	 }
  	 }
    for (int ii=1;ii<=wei;ii++) cc[ii]=c[ii];
  }
}
void jia()
{
    if (len<wei) len=wei; 
	for (int i=1;i<=len+1;i++)
	{
		re[i]+=c[i];
		if (re[i]>=100000000)
		{
		  len++;
		  re[i+1]+=re[i]/100000000;
		  re[i]%=100000000;
	    }
	}
	return ;
}
void jian()
{
	for (int i=1;i<=len;i++)
	{
		re[i]-=c[i];
		if (re[i]<0) 
		 {
		 	re[i+1]--;
		 	re[i]+=100000000;
		 }
	}
    return ;
}
void jiann()
{
	int jg=1;
	re[jg]--;
	while (re[jg]<0)
	{
      re[jg+1]--;
      re[jg]+=100000000;
	}
	return ;
}
int main()
{
	freopen("lan.in","r",stdin);
	freopen("lan.out","w",stdout);
	scanf("%d",&n);
	int ans=0;
    for (int i=1;i<=n;i++)
     {
      scanf("%d",&a[i]);
      if (a[i]==1) 
       {
       	ans++;
       	aa[ans]=i;
       }
	 } 	
    for (int i=ans;i>=1;i--)
    {
    	cheng(aa[i]);
    	if ((ans-i)%2==0) 
    	jia();
    	else jian();	
    	{
    		
    		printf("%d",re[len]);
	  for (int i=len-1;i>=1;i--) 
   	  {
   	  	if (re[i]<10000000)
   	  	 {
   	  	 	int jiji=10000000;
   	  	 	while (re[i]/jiji==0) 
   	  	 	{
   	  	 		printf("0");
   	  	 		jiji/=10;
   	  	 	}
   	  	 }
	    printf("%d",re[i]);
      }
    	}
    }
	 if (ans%2==1)
	  jiann();
	  len++;
	  while (re[len]==0) len--;
	  printf("%d",re[len]);
	  for (int i=len-1;i>=1;i--) 
   	  {
   	  	if (re[i]<10000000)
   	  	 {
   	  	 	int jiji=10000000;
   	  	 	while (re[i]/jiji==0) 
   	  	 	{
   	  	 		printf("0");
   	  	 		jiji/=10;
   	  	 	}
   	  	 }
	    printf("%d",re[i]);
      }
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值