zoukankan      html  css  js  c++  java
  • 题解 CF863C 【1-2-3】

    这道题目小心细节啊!!

    写在前面的话:

    我提交了大概16次才A掉这个题,前12次是因为没有特判循环节长度为0(相信有不少人RE是因为这个原因),也就是没有找到循环节,然后我用k去除以循环节的长度,就疯狂RE.
    后面几次是因为不小心写挂了一个地方,导致死循环了。

    这道题的解题思路:

    观察到给出的两个矩阵的大小仅有(3*3),而且k的大小到了 (10^{18}),当然是找循环节了!很显然,出现的情况无非就是9种:

    1 1
    1 2
    1 3
    2 1
    2 2
    2 3
    3 1 
    3 2
    3 3
    

    考虑用一个数组记录一下每种情况是否出现过,如果出现过,肯定是有循环节,对于循环到的每一种情况采用一个栈储存起来,然后找循环节就是不断退栈.

    找到循环节把每个循环节(不超过9)的输赢情况记录下来,然后直接根据循环节长度计算就行了

    注意特判循环节长度为(0)!!!RE12次血的教训,让人想哭。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long//这是一个坏习惯,但是我懒....
    int a[5][5];//记录矩阵A
    int b[5][5];//记录矩阵B
    int k;
    int A,B;
    bool book[5][5];//用来记录每种情况是否出现
    short tackA[25],tackB[25];//用来记录循环节
    int tail = 0;
    int sorceA = 0,sorceB = 0,len = 0,addA = 0,addB = 0;
    int pd(int x,int y)
    {
    	if(x == 3 && y == 2)return 1;
    	if(x == 2 && y == 1)return 1;
    	if(x == 1 && y == 3)return 1;
    	if(x == y)return -1;
    	return 0;
    }//判断输赢,用了用异或的小技巧
    signed main()
    {
    	cin >> k >> A >> B;
    	for(int i = 1 ;  i <= 3 ; i ++)
    		for(int j = 1 ; j <= 3 ; j ++)
    		cin >> a[i][j];
    	for(int i = 1 ;  i <= 3 ; i ++)
    		for(int j = 1 ; j <= 3 ; j ++)
    		cin >> b[i][j];
    	book[A][B] = 1;
    	int z = pd(A,B);
    	if(z != -1)sorceA += z , sorceB += z^1;
    	k --;tail ++ , tackA[tail] = A,tackB[tail] = B;//先把初始情况入队
    	while(k)//这里是找循环节 
    	{
    		int x = a[A][B] , y = b[A][B];
    		tail ++ , tackA[tail] = x, tackB[tail] = y;
    		if(book[x][y] == 1)break;//如果出现了重复的情况显然就出现了循环
    		book[x][y] = 1;
    		int z = pd(x,y);
    		if(z != -1)sorceA += z , sorceB += z^1;//每次判断输赢
    		A = x , B = y;//记录上一次的结果
    		k --;
    	}
    	int X = tackA[tail],Y = tackB[tail];
    	tail --;
    	while(tail)// 退栈
    	{
    		len ++;
    		int z = pd(tackA[tail],tackB[tail]);
    		if(z != -1)addA += z , addB += z^1;
    		if(tackA[tail] == X && tackB[tail] == Y)break;
    		tail --;//找循环节
    	}
    	if(len != 0){
    		sorceA += (k/len)*addA , sorceB += (k/len)*addB;
    		k %= len;
    	}
    	while(k > 0)//此时的k一定小于循环节
    	{
    		int X = tackA[tail] , Y = tackB[tail];
    		int z = pd(X,Y);
    		if(z != -1)sorceA += z , sorceB += z^1;
    		k --;
    		tail ++;//我退了栈,实际上元素还待在栈里面,我回溯找回元素来计算
    	}
    	cout << sorceA << " " << sorceB;
    	return 0;
    }
    
  • 相关阅读:
    ubuntu 9.04更新源
    想学一下asp.net,跟着书本做了个bbs
    [转]ubuntu系统中遇到的一些问题及解决
    第一篇,打个招呼
    人际交往的书籍推荐
    程序员的五层境界,你在哪一层?
    HTTP报文之"请求报文"和"响应报文"详解
    如何提高你的工作效率?
    面对焦虑我们怎么办 ?
    CEO要看的书籍推荐
  • 原文地址:https://www.cnblogs.com/MYCui/p/13869885.html
Copyright © 2011-2022 走看看