zoukankan      html  css  js  c++  java
  • 【TJOI2017】可乐

    题目描述

    加里敦星球的人们特别喜欢喝可乐。因而,他们的敌对星球研发出了一个可乐机器人,并且放在了加里敦星球的(1)号城市上。这个可乐机器人有三种行为:停在原地,去下一个相邻的城市,自爆。它每一秒都会随机触发一种行为。现在给出加里敦星球城市图,在第(0)秒时可乐机器人在(1)号城市,问经过了(t)秒,可乐机器人的行为方案数是多少?

    输入格式

    第一行输入两个正整数(N,M),(N)表示城市个数,(M)表示道路个数。((1≤N≤30),(0≤M≤100))

    接下来M行输入(u,v),表示(u,v)之间有一条道路。((1≤u,v≤n))保证两座城市之间只有一条路相连。

    最后输入时间(t)

    输出格式

    输出可乐机器人的行为方案数,答案可能很大,请输出对(2017)取模后的结果。

    数据范围

    对于20%的数据,有(1<t≤1000)
    对于100%的数据,有(1<t≤10^6)


    一开始看着数据范围还以为是一道卡常数题啊......

    这个保证(t≤10^6),直觉不会想到(logt)啊QAQ


    显然,如果这道题目是卡常数题的话,那就是一道很简单的小学生dp了

    (f[i][j][0])表示第(i)时刻,在城市(j)爆炸的方案数,(f[i][j][1])表示第(i)时刻,在城市(j)不爆炸的方案数

    (f[i][j][0]=f[i-1][j][0]+f[i-1][j][1]),(f[i][j][1]=f[i][j][1]+f[i][k][1])((k)(j)的相邻结点)

    这样是要MLE的,显然状态的答案只与前一状态相关,直接滚动即可

    事实证明,这样只有20分


    看起来这是一阶递推,考虑用矩乘来优化

    先考虑(f[i][j][1]=f[i][j][1]+f[i][k][1]),可以发现,如果我们假设(i)结点和自己本身相邻的话,可以将前一项并到后一项当中

    我们可以用一个(n*n)的矩阵(A)(f[0][?][1])构成的矩阵(B)相乘得到,而(n*n)的矩阵是表示是否直接相邻的邻接矩阵,特别的(A[i][i]=1)

    这样的话,我们对(A)矩阵快速幂即可

    继续考虑(f[i][j][0]=f[i-1][j][0]+f[i-1][j][1]),我们可以发现,这其实是(sum f[i-1][j][1]),按照前一个幂的处理,可以发现,这其实是一个矩阵的等比数列

    直接按照等比数列求个和就好了咯

    时间复杂度(O(nlogn))

    #include<cstdio>  
    #include<iostream>  
    #include<algorithm>  
    #include<cstdlib>  
    #include<cstring>
    #include<string>
    #include<climits>
    #include<vector>
    #include<cmath>
    #include<map>
    #define LL long long
     
    using namespace std;
     
    inline char nc(){
      static char buf[100000],*p1=buf,*p2=buf;
      if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
      return *p1++;
    }
     
    inline void read(int &x){
      char c=nc();int b=1;
      for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
      for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
    }
     
    inline void read(LL &x){
      char c=nc();LL b=1;
      for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
      for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
    }
    
    inline int read(char *s)
    {
    	char c=nc();int len=0;
    	for(;!((c>='A' && c<='Z')||(c>='a' && c<='z'));c=nc()) if (c==EOF) return 0;
    	for(;((c>='A' && c<='Z')||(c>='a' && c<='z'));s[len++]=c,c=nc());
    	s[len++]='';
    	return len;
    }
    
    inline void read(char &x){
      for (x=nc();!(x=='?' || x=='+' || x=='-');x=nc());
    }
    
    int wt,ss[19];
    inline void print(int x){
    	if (x<0) x=-x,putchar('-'); 
    	if (!x) putchar(48); else {
    	for (wt=0;x;ss[++wt]=x%10,x/=10);
    	for (;wt;putchar(ss[wt]+48),wt--);}
    }
    inline void print(LL x){
    	if (x<0) x=-x,putchar('-');
    	if (!x) putchar(48); else {for (wt=0;x;ss[++wt]=x%10,x/=10);for (;wt;putchar(ss[wt]+48),wt--);}
    }
    
    int n,m,T,f[40],g[40];
    const int mo=2017;
    struct data
    {
    	int f[40][40];
    }a,b;
    
    void add(data &x,data y)
    {
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=n;j++)
    			x.f[i][j]=(x.f[i][j]+y.f[i][j])%mo;
    }
    
    void mul(data &x,data y)
    {
    	data z;
    	memset(z.f,0,sizeof(z.f));
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=n;j++)
    			for (int k=1;k<=n;k++)
    				z.f[i][j]=((x.f[i][k]*y.f[k][j])%mo+z.f[i][j])%mo;
    	x=z;
    }
    
    data Power(data x,int y)
    {
    	data res;
    	memset(res.f,0,sizeof(res.f));
    	for (int i=1;i<=n;i++)
    		res.f[i][i]=1;
    	for (;y;y>>=1)
    	{
    		if (y&1) mul(res,x);
    		mul(x,x);
    	}
    	return res;
    }
    
    data Sum(data x,int y)
    {
    	data res;
    	memset(res.f,0,sizeof(res.f));
    	if (y==0) return res;
    	if (y==1) return x;
    	for (int i=1;i<=n;i++)
    		res.f[i][i]=1;
    	add(res,Power(x,y>>1));mul(res,Sum(x,y>>1));
    	if (y&1) add(res,Power(x,y));
    	return res;
    }
    
    int main()
    {
    	read(n);read(m);
    	int x,y;
    	memset(a.f,0,sizeof(a.f));
    	for (int i=1;i<=m;i++)
    		read(x),read(y),a.f[x][y]=1,a.f[y][x]=1;
    	for (int i=1;i<=n;i++)
    		a.f[i][i]=1;
    	read(T);
    	b=a;
    	a=Power(a,T);
    	memset(g,0,sizeof(g));
    	memset(f,0,sizeof(f));
    	g[1]=1;
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=n;j++)
    			f[i]=((g[j]*a.f[i][j])%mo+f[i])%mo;
    	int ans=0;
    	for (int i=1;i<=n;i++)
    		ans=(ans+f[i])%mo;
    	b=Sum(b,T-1);
    	for(int i=1;i<=n;i++)
    		b.f[i][i]=(b.f[i][i]+1)%mo; 
    	memset(g,0,sizeof(g));
    	memset(f,0,sizeof(f));
    	g[1]=1;
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=n;j++)
    			f[i]=((g[j]*b.f[i][j])%mo+f[i])%mo;
    	for (int i=1;i<=n;i++)
    		ans=(ans+f[i])%mo;
    	print(ans),puts("");
    	return 0;
    }
    
    
  • 相关阅读:
    input文本框输入限制(正则表达式)
    SQL Server通用型分页存储过程
    简单易学的数据图表
    HTML中input文本框只读不可编辑的方法
    SQL添加外键约束的方式
    +1 也要睁着眼
    博客园的自定义皮肤
    网站收集整理
    jQuery extend方法介绍
    HTML5本地存储
  • 原文地址:https://www.cnblogs.com/xiejiadong/p/6814145.html
Copyright © 2011-2022 走看看