ACM解题报告

 
Kiki & Little Kiki 2
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 529    Accepted Submission(s): 303
Problem Description
There are n lights in a circle numbered from 1 to n. The left of light 1 is light n, and the left of light k (1< k<= n) is the light k-1.At time of 0, some of them 

turn on, and others turn off. Change the state of light i (if it's on, turn off it; if it is not on, turn on it) at t+1 second (t >= 0), if the left of light i is on 

!!! Given the initiation state, please find all lights’ state after M second. (2<= n <= 100, 1<= M<= 10^8)
 

Input
The input contains one or more data sets. The first line of each data set is an integer m indicate the time, the second line will be a string T, only contains '0' and 

'1' , and its length n will not exceed 100. It means all lights in the circle from 1 to n.If the ith character of T is '1', it means the light i is on, otherwise the 

light is off.
 

Output
For each data set, output all lights' state at m seconds in one line. It only contains character '0' and '1.
 

Sample Input
1 0101111 10 100000001
 

Sample Output
1111000 001000010
/* 先说说这个题的意思,正如上面的红字所示,当它左边的灯为开的时候改变自己的状态依此循环,判断左边的灯是在改变之前判断 

上面的输入1 0101111  是1s后整体灯的状态,  由于这个 1<= M<= 10^8  时间的取值范围会非常大,会导致典型的超时,那样该怎么做呢?这种题是典型的矩阵求解题,为什么是矩阵,我

们给出一个解说

我们刚开始学了现形代数里的 矩阵 一直觉得那个不知道怎么用,现在我们来讨论它的一种应用
我们先来说矩阵的一个优点 它是将 所有一组操作集合在一个矩阵中,然后只需要一步操作就能得出最后操作结果(在这里我们会用矩阵的幂 乘以 初始状态得到最终状态)(在这里有人可能会

说 那矩阵的幂不是需要更多的时间(我们用二分法 时间复杂度由 n变为O(log(2)(N)
什么概念呢 比如原来是2^64即为18466744073709551616次 现在就变成了O(log(2)(2^64)即为64次(由原来的20位数变成了现在的2位数64 是不是很快呢))
有一个递推式 A(n) = A(n-1) -- 2*A(n-2) + 3A(n-3) -- A(n-4) 并且知道A(0)=0;A(1)=1;A(2)=2;A(3)=3; 怎么求出A(n)呢 ?
为了求这个我们先来说明一个简单的问题:
A(n)=A(n-1) + A(n-2);A(0)=1;A(1)=1;

A(n)      1   1       A(n-1)
        =         *    
A(n-1)    1   0       A(n-2)  
        
 1   1        1  1       A(n-2)
=      *       *                 = ..........
 1   0    1  0    A(n-3)

  | 1  1 |^(n-1)  A(1)
= |      |     * 
	| 1  0 |       A(0)
	
看懂了吧!那我们现在来求上面的问题
A( n)      | 1  -2  3  -1 |^(n-3)   A(3)
A( n-1)    | 1   0  0  0 |          A(2)
       =   |             |  *
A( n-2)    | 0   1  0  0 |          A(1)
A( n-3)    | 0   0  1  0 |          A(0)
  
这够详细吧。但是由于时间范围取的很大,相乘次数会太多,怎么解决呢?其实上面已经稍微提了一下,那就是强悍的二分法,怎么用呢?把每个矩阵当成一个数 这样就好了,好了还是看如

下AC过的代码吧*/
/*矩阵 加 二分*/
#include <stdio.h>  
#include <string.h>  

#define size 103

/*  例如:  10  100000001  初始表  
/*构造矩阵*//*1 0 0 0 0 0 0 0 1 
	      1 1 0 0 0 0 0 0 0 
	      0 1 1 0 0 0 0 0 0 
	      0 0 1 1 0 0 0 0 0 
	      0 0 0 1 1 0 0 0 0 
	      0 0 0 0 1 1 0 0 0 
	      0 0 0 0 0 1 1 0 0 
	      0 0 0 0 0 0 1 1 0 
	      0 0 0 0 0 0 0 1 1 
 
输入表        1 0 0 0 0 0 0 0 0 
	      0 0 0 0 0 0 0 0 0  
	      0 0 0 0 0 0 0 0 0
	      0 0 0 0 0 0 0 0 0  
	      0 0 0 0 0 0 0 0 0
	      0 0 0 0 0 0 0 0 0
	      0 0 0 0 0 0 0 0 0
	      0 0 0 0 0 0 0 0 0
              1 0 0 0 0 0 0 0 0  
结果所求的矩阵为 构造矩阵^n * 输入矩阵,每一个元素的值为乘积值mod 2 //这儿很重要 */ 
/*
 为什么是对2取余呢? 我们从上面的总结出状态方程 
A1 = (A1 +An)%2 
A2 = (A1 +A2)%2 
.......
状态方程为 Ai = (Ai + A(i-1))&1
|1 0 0 0···0 0 1 | a1  		|a1+an| 
|1 1 0 0··· 0 0 0| a2  		|a1+a2| 
|0 1 1 0 ···0 0 0| a3 	=	|a2+a3| 
|0 0 1 1 ···0 0 0| a4  		|a3+a4| 
|           ·· | ai   		|……...|  
这样构造矩阵的哦

*/ 

	int t,len;   
	char s[size];
        struct node    {
	       int Graph[size][size];
	}unit,init,right;
	
        void InitData(int len)   //初始化构造矩阵 
	{
	       int i,j;
	 
	      for (i=0;i<len;i++)
	      {
	           for (j=0;j<len;j++)           		   {
              		 unit.Graph[i][j] = (i==j);
	                 init.Graph[i][j] = right.Graph[i][j] = 0;
	           }
       	      }       
	      init.Graph[0][0] = init.Graph[0][len-1] = 1;
       	      for(i=1;i<len;i++)
	           init.Graph[i][i-1] = init.Graph[i][i] = 1;
		       for(i=0;i<len;i++)
		           right.Graph[i][0] = s[i]-'0';
        }

        node Mul(node a,node b)   //矩阵的乘法
	{
	       int i,j,k;
	       node c;

	       for (i=0;i<len;i++)
 	       {
	           for (j=0;j<len;j++)
	           {
	               c.Graph[i][j] = 0;              		 for (k=0;k<len;k++)
                   		c.Graph[i][j]+=a.Graph[i][k]*b.Graph[k][j];
		                c.Graph[i][j]%=2;
           	   }
   	       }
 
              return c;
       }
   	node Cal()   //二分法求矩阵的幂
	{
           node p,q;
	   p = unit,q = init;
	       while (t)
	       {
	           if(t&1)   //是奇数 则p叠乘上
	              p = Mul(p,q);           		      t>>=1;   //右移,相当于/2
	              q = Mul(q,q);
	       }
	       p = Mul(p,right);

          return p;
       }

   int main()   
   {
    	freopen("in.txt","r",stdin);
    	int i;
        node res;

        while (scanf("%d",&t)!=EOF)
        {
           scanf("%s",s);
           len = strlen(s);
           InitData(len);
           res = Cal();
           for(i=0;i<len;i++)
               printf("%d",res.Graph[i][0]);
	   
	   printf("\n");
        }

       return 0;
   }
 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值