zoukankan      html  css  js  c++  java
  • 2018牛客网暑假ACM多校训练赛(第四场)A Ternary String 数论

    原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round4-A.html

    题目传送门 - https://www.nowcoder.com/acm/contest/142/A

    题意

      给定一个长度为 $n$ ,只包含 $0,1,2$ 的数列。

      每一秒会依次进行如下操作:

      1. 所有的 $1$ 后面生出一个 $0$

      2. 所有的 $2$ 后面生出一个 $1$ 

      3. 第一个数字消失了

      问经过多少时间之后,数列全部消失。

      多组数据。

      答案对于 $10^9+7$ 取模。 $nleq 10^5,sum nleq 2 imes 10^6$

    题解

      假设当前时间为 $t$ ,我们可以简单推一波式子分别得到消灭下一个数字及其生出来的数字之后的时间:

      如果下一个数字是   :则

              0 : $t^prime=t+1$

              1 : $t^prime=2t+2$

              2 : $t^prime=6 imes 2^t-3$

      那么由于 $t$ 会出现在指数上面,我们不能随意将 $t$ 对 $10^9+7$ 取模。

      我当场写了个 $O(nlog n)$ 的,一个有点低级的错误续了我很久(看来昨天念诗之后还有后遗症啊)

      考虑欧拉定理:

      当 $gcd(a,b)=1$ 时,$a^{phi (b)}equiv 1 pmod b$ 。

      由于这里 $a=2$ ,所以我们可以进行推广。

      记 $b=x imes 2^y,a=2^{k+y}$ ,则当 $kgeq 0$ 时 :

    $$2^{k+y}equiv 2^{(k mod {phi(x)}) + y}pmod {x imes 2^y}$$

      于是我们可以使 $k$ 取模。

      但是如果 $k<0$ 呢,那么显然这个数字很小,直接算出来。

      注意一下 $y$ 的值也是很小的。

      我们处理一下前面较小的一部分的答案,然后从后往前根据上式递归求解即可。

      时间复杂度 $O(nlog n)$ 。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=100005;
    int T,ps[N],x[N],y[N],px[N],pt[N];
    char s[N];
    int Pow(int x,int y,int mod){
    	int ans=1;
    	for (;y;y>>=1,x=1LL*x*x%mod)
    		if (y&1)
    			ans=1LL*ans*x%mod;
    	return ans;
    }
    int phi(int x){
    	int ans=x;
    	for (int i=2;i*i<=x;i++){
    		if (x%i==0){
    			ans=ans/i*(i-1);
    			while (x%i==0)
    				x/=i;
    		}
    	}
    	if (x>1)
    		ans=ans/x*(x-1);
    	return ans;
    }
    int solve(int j,int k){
    	if (j==0||pt[j]>0)
    		return pt[j];
    	int i=j;
    	while (i>0&&s[i]!='2')
    		i--;
    	int t=i==0?0:((6LL*Pow(2,solve(i-1,k+1),x[k])-3)%x[k]);
    	for (int p=i+1;p<=j;p++){
    		if (s[p]=='0')
    			t=(t+1)%x[k];
    		if (s[p]=='1')
    			t=(2*t+2)%x[k];
    	}
    	t=((t-y[k])%x[k]+x[k])%x[k];
    	return t+y[k];
    }
    int main(){
    	ps[0]=1e9+7;
    	for (int i=1;i<=100000;i++)
    		ps[i]=phi(ps[i-1]);
    	for (int i=1;i<=100000;i++){
    		for (x[i]=ps[i-1],y[i]=0;x[i]%2==0;x[i]>>=1,y[i]++);
    		x[i]=phi(x[i]);
    	}
    	x[0]=ps[0],y[0]=0;
    	scanf("%d",&T);
    	while (T--){
    		scanf("%s",s+1);
    		int n=strlen(s+1),i=0;
    		for (int x=0;i<n;i++,pt[i]=x){
    			if (s[i+1]=='0')
    				x++;
    			if (s[i+1]=='1')
    				x=x*2+2;
    			if (s[i+1]=='2')
    				x=6*Pow(2,x,1e9+7)-3;
    			if (x>=21)
    				break;
    		}
    		printf("%d
    ",(solve(n,0))%ps[0]);
    		for (;i>0;i--)
    			pt[i]=0;
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    用SQL SERVER取分组数据第一条:查出每个班级的成绩第一名
    [转]spring beans.xml
    [转]为什么要使用框架
    MySQL 5.6 for Windows 解压缩版配置安装
    [转]hql 语法与详细解释
    [转]slf4j + log4j原理实现及源码分析
    [转]最详细的Log4j使用教程
    yii2 checkbox 的使用实例
    Magento Order 状态详解
    yii2 设置多个入口文件
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round4-A.html
Copyright © 2011-2022 走看看