ccf 1246 The most detailed rookie analysis

ccf 1246

Insert picture description here
We don't expect a 100-point code. I will send a 96-point code for your reference.
Question link: http://118.190.20.162/view.page?gpid=T102
Insert picture description here
Observing the test points and knowing that most test points have only one or two s. For the last test point, like it just gave up.
Observing the test points and the length of the string, we can know that when n is large enough, the length of the string will become huge, and the violent method will definitely not work. So a certain rule is needed.

Observation shows that there are only 14 cases where s is one or two digits in the string.
One bit: 1, 2, 4, 6
Two bits: 16, 26, 41, 42, 44, 46, 61, 62, 64, 66

Observing the string again, you can get a relationship diagram like this: (Too lazy to draw, I used another blogger’s diagram directly, link: https://www.pythonheidong.com/blog/article/433221/) Insert picture description here
Through this A relationship graph, we can get the recurrence relationship between the previous string and the next string. The prototype of the idea came out, and the use of dynamic programming should be able to solve this problem.
Two-digit bifurcation principle: For example, 16, it is divided into the first power of 2 and the sixth power of 2.

By this figure we can see that:
the next string 2 may be composed of a string of 1 was
obtained under 4 may be made of a string of a string 2 on the
next string of a string of 1 and 6 may be obtained by the above 4
so By analogy, we can get the recurrence relationship when s is one bit.

The next is difficult point one, how to get the recurrence relationship when s is two digits.
In fact, we modified the above diagram and combined the original non-adjacent ones, and found that the same effect can be obtained.
For example: 16 can produce 264, which can be divided into (26)4, and 26 can be obtained
. The ideological problem to be solved here is why 264 only counts one 26, and why not count other combinations.
Because other combinations are already counted when s is one digit, there will be repetitions, and 26 is a combination of two different two numbers, and it will not be counted when s is one digit. count.

After understanding the above ideas, we can get the comparison table 1:
Insert picture description here
Its meaning is: the number of 1 in the previous string is equal to the number of 2 in the next string. That is, the 1 in the previous string becomes 2 in the next string through the appeal relationship. After
understanding the comparison table, we need to extract the recurrence relationship from the comparison table. And perform numbering processing to get the recurrence relationship table.
Insert picture description here
Through the comparison table, we can get the following recurrence table, and then number the recurrence table.
The recurrence table in the above figure tells us:
the 1 in the next string is obtained from the 4 in the previous string.
The 4 in the next string is obtained from the 4 and 6 in the previous string.

Through the recurrence table and digital number, the recurrence relationship is obtained:
similar:
f(i)(1)=f(i-1)(3)
f(i)(2)=f(i-1)(1)
f (i)(3)=f(i-1)(2)+f(i-1)(4)
f(i)(4)=f(i-1)(3)+f(i-1) (4)

At this point, the recurrence relationship of each number in the string is obtained, and how to deal with the recurrence has become the current problem.

To give a simple example, the Fibonacci sequence is a very classic recurrence relationship.
f(n)=f(n-1)+f(n-2)
If [f(n-1), f(n-2)] is regarded as a vector, then this vector is multiplied by the matrix [[1 , 1] [1, 0]] can get a new vector [f(n), f(n-1)].
This is to use the matrix to advance the recurrence relationship. That is, the previous state of the recursion is multiplied by a matrix to get the next state of the recursion. This idea is one of the key points of breaking the problem.

Then we understand the next key point of breaking the problem. It is fast power. Asking for 2^16, we may recall that we multiply 16 2s. This way of course can get the result, but when the power is large enough, this calculation method is very stretched. So we introduce fast power.
When the first two 2 are multiplied, we change the original question to 4^8. Repeating such operations can reduce a lot of calculations. When the power changes to an odd number, a single power is taken out, and then the remaining even-numbered powers are continued to perform fast exponentiation, and finally the odd-numbered powers taken out are multiplied back.

After understanding the matrix recursion thought and fast power thought, combined with the appealed recurrence relation, the calculation can be carried out.
Of course, the difficulty is that the recurrence is related to the conversion process of the matrix, this process cannot help, you need to understand it yourself.

Insert picture description here
This is the dp matrix corresponding to the recurrence relationship of 14. Note that the vector direction of this dp matrix is ​​vertical. )

Initial result set:
Insert picture description here

Using the new combination of matrix multiplication, we can use the fast exponentiation method to find the product of all matrices, and then multiply the calculated matrix into the result set to get the result directly. If an odd power appears in the middle, the odd power is taken out and multiplied into the result set first, and the remaining even powers continue to perform fast exponentiation.

Of course, it may be difficult to understand the 14-bit matrix recursion directly. You can use the
Insert picture description here
four-bit matrix and the four-bit result set to perform the recursive understanding, and then expand to 14 bits.

On the code:

import java.util.Scanner;
import java.util.Map;
import java.util.HashMap;;

//快速幂+dp递推矩阵
class Matrix{
    
    	
	public long[][] Ma_Ma(long [][] dp){
    
    //类似这种值很大的题目,尤其需要关注结果范围和考虑溢出。
		int n=dp.length;
		long [][] temp=new long[n][n];
		//两个相同的矩阵相乘,dp递推矩阵相乘
		for(int i=0;i<n;i++) {
    
    
			for(int j=0;j<n;j++) {
    
    
				for(int k=0;k<n;k++) {
    
    
					temp[i][j]+=(dp[i][k]*dp[k][j]);
					temp[i][j]%=998244353;//结果太大,如果不进行取余操作,会结果溢出,出现负值
				}
			}
		}
		return temp;
	}
	
	public long[] Ma_Ve(long [][] dp,long []res) {
    
    
		int n=dp[0].length;//矩阵的列数
		int m=res.length;
		long [] temp=new long[m];
		//结果向量与矩阵相乘
		for(int i=0;i<n;i++) {
    
    
			for(int j=0;j<m;j++) {
    
    
				temp[i]+=(res[j]*dp[i][j]);
				temp[i]%=998244353;//结果太大,如果不进行取余操作,会结果溢出,出现负值
			}
		}
		return temp;
	}
}

public class DP {
    
    
	public static void main(String[] args) {
    
    
		//初始的结果向量(n=0)时。
		long [] res =new long[14];
		res[0]=1;
		//dp矩阵,矩阵向量方向是行方向,第一次因为乘了列方向的向量,导致错误。
		long [][] dp= 
			{
    
    {
    
    0,0,1,0,0,0,0,0,0,0,0,0,0,0},
			{
    
    1,0,0,0,0,0,0,0,0,0,0,0,0,0},
			{
    
    0,1,0,1,0,0,0,0,0,0,0,0,0,0},
			{
    
    0,0,1,1,0,0,0,0,0,0,0,0,0,0},
			{
    
    0,0,1,0,0,0,0,0,0,0,0,0,0,0},
			{
    
    0,0,0,0,1,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,0,0,0,1,0,0,0},
			{
    
    0,0,0,0,0,0,0,0,0,0,0,1,0,0},
			{
    
    0,0,0,0,0,1,0,0,0,0,0,0,0,1},
			{
    
    0,0,0,0,0,0,0,0,1,0,0,0,0,0},
			{
    
    0,0,0,0,0,0,1,0,0,0,0,0,0,0},
			{
    
    0,0,0,1,0,0,0,1,0,0,0,0,0,0},
			{
    
    0,0,0,0,0,0,0,0,0,1,0,0,0,0}
			};
		//对照表
		Map<Integer,Integer> map=new HashMap<Integer,Integer>();
		map.put(1,0);
		map.put(2,1);
		map.put(4,2);
		map.put(6,3);
		map.put(16,4);
		map.put(26,5);
		map.put(41,6);
		map.put(42,7);
		map.put(44,8);
		map.put(46,9);
		map.put(61,10);
		map.put(62,11);
		map.put(64,12);
		map.put(66,13);
		
		Scanner in=new Scanner(System.in);
		int n=in.nextInt();
		int s=in.nextInt();
		in.close();
		
		Matrix ma=new Matrix();
		//快速幂核心代码
		//利用矩阵乘法的交换性和结和性。先算后面所有矩阵的矩阵乘法,把最后得到的矩阵乘入结果向量,得到最终结果。
		//快速幂思想,就是利用上一次的计算结果作为新的基数,使得计算技术指数式减少。
		//当遇见幂数为奇数时,就先取出一个乘进结果集,剩下的偶数幂再进行快速幂运算
		while(n>0) {
    
    
			if(n%2==1) {
    
    
				res=ma.Ma_Ve(dp, res);
			}
			dp=ma.Ma_Ma(dp);
			n>>=1;//移位运算
		}
		
		System.out.print(res[map.get(s)]);
		
	}
}

Guess you like

Origin blog.csdn.net/weixin_43797829/article/details/108686867