zoukankan      html  css  js  c++  java
  • Codewars. Insane Coloured Triangles(计数)

    题目链接
    加强版:Ludicrous Coloured Triangles

    虽然题不难但难得做一个来水一下

    有dalao知道加强版怎么过嘛


    (Description)
    给定长为(n)的RGB序列,每次变换,序列中所有相邻的两个字符会产生一个字符(即每次总长度减1)。求(n-1)次变换后剩下的那个字符是多少。
    字符产生规则:相同的两个字符产生相同的字符(如RR->R),不同的两个字符产生没出现的第三类字符(如RG->B)。
    (n-1)次变换的例子如下,可知R R G B R G B B应输出G

    R R G B R G B B
     R B R G B R B
      G G B R G G
       G R G B G
        B B R R
         B G R
          R B
           G
    

    (nleq 10^5)
    Ludicrous Coloured Triangles为加强版:(nleq 10^9)

    (Solution)
    Sol 1.
    容易想到将(R,G,B)看做(0,1,2),则不同颜色(a,b)转成第三者就是(3-a-b)
    然后可发现,(a,b)颜色相同时,((3-a-b+3)\%3)也能正确表示同色的情况,即((3-2a+3)\%3==a)
    所以每一次操作,就是将相邻两个颜色(a,b)变为((6-a-b)\%3),即(-a-b)然后取模下。只要算 到最后一层时,每个元素(x)被累积了几次,用(x)乘以这个次数即可。
    可以猜到,第(i)个位置的元素会被累积(C_{n-1}^i)次(下标从(0)开始)。因为就是从((1,i))往下走,走到((n,n/2))前可以在任意行选择向右/左走(i)次。
    其实也就是个倒置的杨辉三角。

    所以答案为:(sum_{i=0}^{n-1}value(s[i])*inom{n-1}{i}\%3)(最后根据(n)奇偶性取正或负)。

    (C_{n-1}^i)可以用(frac{n-1-i+1}{i})递推。注意因为是(mod 3)(i)的逆元就是(i),所以就是((n-1-i+1)*i\%3),可以(O(n))递推
    注意模数(3)太小,组合数不能递推或用阶乘算,要Lucas。。
    复杂度(O(nlog_3n))

    btw,将颜色(a,b)转化也可以使用(2*(a+b)\%3),最后是有个(2^{n-1})而不是((-1)^{n-1})

    CPP代码:

    #include <bits/stdc++.h>
    typedef long long LL;
    const int N=1e5+5;
    using std::string;
    
    int fac[3]={1,1,2};
    #define Val(c) (c=='R'?0:c=='G'?1:2)
    #define Char(v) (v==0?'R':v==1?'G':'B')
    int C(int n,int m)//inv(x)==x
    {
    	return n<m ? 0 : fac[n]*fac[m]*fac[n-m]%3;
    }
    int Lucas(int n,int m)
    {
    	int ans=1;
    	for(; m && ans; n/=3, m/=3) (ans*=C(n%3,m%3))%=3;
    	return ans;
    }
    char triangle(const std::string &row)
    {
    	int n=row.length()-1;
    	if(!n) return row[0];
    	int i=0, ans=0;
    	for(auto c: row) ans+=Val(c)*Lucas(n,i), ++i;
    	return ans=(n&1?3-ans%3:ans)%3, Char(ans);
    }
    
    int main()
    {
    	string str;
    	std::cin>>str;
    	printf("%c",triangle(str));
    
    	return 0;
    }
    

    Python代码:

    fac = [1, 1, 2]
    def C(n, m): # inv(x)==x
    	return 0 if n<m else fac[n]*fac[m]*fac[n-m]%3
    def Lucas(n, m):
    	ans = 1
    	while m and ans:
    		ans, n, m = ans*C(n%3, m%3)%3, n//3, m//3
    	return ans
    def triangle(row):
    	i, ans, n = 0, 0, len(row)-1
    	if not n: return row
    	for c in row:
    		ans, i = ans+(0 if c=='R' else 1 if c=='G' else 2)*Lucas(n,i), i+1
    	ans=(3-ans%3 if n&1 else ans)%3
    	return 'R' if ans==0 else 'G' if ans==1 else 'B'
    
    print(triangle('GB'))
    print(triangle('RGBG'))
    print(triangle('RBRGBRB'))
    

    Sol 2.
    有一个性质:任意长为4的序列,其最终结果只与第一个和最后一个字符有关(而且是同样的转换原则)。
    然后,对任意长为(3^k+1)的序列,其结果也有规律。具体是什么我已经不想去想了...
    总之有如下的最多(O(log_3^2n))的做法(但是依旧无法过Ludicrous Coloured Triangles...):

    rules = {'RR': 'R', 'GG': 'G', 'BB': 'B',
             'BG': 'R', 'RB': 'G', 'RG': 'B',
             'GB': 'R', 'BR': 'G', 'GR': 'B'}
    
    from math import log
    
    def triangle(row):
        n = len(row)
        if n == 1:
            return row
        d = n - 3**int(log(n-1, 3))
        return rules[triangle(row[:d]) + triangle(row[-d:])]
    

    Sol 3.
    Solution里有很多其他人的神仙过题代码... 具体不想了解,摘抄几个:

    def triangle(row):
        reduce=[3**i+1 for i in range(10) if 3**i<=100000][::-1]
        for length in reduce:
            while len(row)>=length:
                row=[row[i] if row[i]==row[i+length-1] else ({"R","G","B"}-{row[i],row[i+length-1]}).pop() for i in range(len(row)-length+1)]
        return row[0]
    
    #include <map>
    #include <string>
    using namespace std;
    char triangle(string r){
      map<string, char> mp = {{"RR", 'R'}, {"BB", 'B'}, {"GG", 'G'}, {"BG", 'R'}, {"BR", 'G'}, {"GB", 'R'}, {"GR", 'B'}, {"RB", 'G'}, {"RG", 'B'}};
      while(r.size() > 1){
        string n = "";
        int c = 1;
        while(r.size() % (3 * c) == 1) c *= 3;
        for (int i = 0; i < r.size() - 1; i += c){
            string x = "";
            x += r[i];
            x += r[i + c];
            n += mp[x];
        }
        r = n;
      }
      return r[0];
    }
    

    无心插柳柳成荫才是美丽
    有哪种美好会来自于刻意
    这一生波澜壮阔或是不惊都没问题
    只愿你能够拥抱那种美丽

  • 相关阅读:
    引入包时“”与<>的区别
    Scanners
    一个SQLite数据库的LIKE查询和IN集合查询的代码实例
    @synchronized线程同步互斥锁
    makeKeyAndVisible
    NSString 数字判断
    UILabel UITextField UITextView
    (转载)JAVA SE6.0 中使用SplashScreen
    转帖(http://hi.baidu.com/johnehuang/blog/item/e1e96782a4b04e97f703a6dc.html)
    ce
  • 原文地址:https://www.cnblogs.com/SovietPower/p/15254321.html
Copyright © 2011-2022 走看看