题解:ACM-ICPC 2018 焦作赛区网络预赛

版权声明:本文为博主原创文章,欢迎转载并注明来源。 https://blog.csdn.net/w_weilan/article/details/82768705

Magic Mirror

#include <cstdio>
#include <cstring>
int T;
char s[20],a[20]="JESSIE",b[20]="jessie";
bool o;
int main()
{
	scanf("%d",&T);
	while (T--)
	{
		scanf("%s",s);
		if (strlen(s)!=6) 
		{
			printf("Dare you say that again?\n");
			continue;
		}
		o=true;
		for (int i=0;i<6;i++)
		 if ((s[i]!=a[i])&&(s[i]!=b[i]))
		 {
		 	o=false;
		 	break;
		 }
		if (o) printf("Good guy!\n");
		 else printf("Dare you say that again?\n");
	}
	return 0;
}

Mathematical Curse

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int t,n,m,k;
long long a[1010]; 
char s[10];
long long mx[1010][10],mn[1010][10];
int main()
{
	scanf("%d",&t);
	while (t--)
	{
		scanf("%d%d%d",&n,&m,&k);
		for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
		scanf("%s",s);
		memset(mx,0,sizeof(mx));
		memset(mn,0,sizeof(mn));
		mx[0][0]=mn[0][0]=k;
		for (int i=1;i<=n;i++)
		 for (int j=1;(j<=m)&&(j<=i);j++)
		 {
		 	mx[i][0]=mn[i][0]=k;
		  	if (s[j-1]=='+') mx[i][j]=mx[i-1][j-1]+a[i],mn[i][j]=mn[i-1][j-1]+a[i];
		   	 else if (s[j-1]=='-') mx[i][j]=mx[i-1][j-1]-a[i],mn[i][j]=mn[i-1][j-1]-a[i];
		      else if (s[j-1]=='*') 
			  {
			  	if (a[i]>=0) mx[i][j]=mx[i-1][j-1]*a[i],mn[i][j]=mn[i-1][j-1]*a[i];
			  	 else mx[i][j]=mn[i-1][j-1]*a[i],mn[i][j]=mx[i-1][j-1]*a[i];
			  }
			   else 
			   {
			   	if (a[i]>=0) mx[i][j]=mx[i-1][j-1]/a[i],mn[i][j]=mn[i-1][j-1]/a[i];
			   	 else mx[i][j]=mn[i-1][j-1]/a[i],mn[i][j]=mx[i-1][j-1]/a[i];
			   }
			if (i>j) mx[i][j]=max(mx[i][j],mx[i-1][j]),mn[i][j]=min(mn[i][j],mn[i-1][j]);	
		 }	
		printf("%lld\n",mx[n][m]);
	}
	return 0;
} 

Password

Sequence

Jiu Yuan Wants to Eat

链剖+双标记维护区间和,区间取反操作等价于区间乘-1后区间加-1
时限卡的有点紧,线段树一开始用vector建的时候会T,改成数组也要跑2700ms/3000ms。

#include<cstdio>
#include<vector>
using namespace std;
typedef unsigned long long ll;
const int N=2e5+9;
struct Node
{
	ll sum,add,mul;
} v[N<<2];
struct SegmentTree
{
	SegmentTree(int N)
	{
		build(1,N,1);
	}
	void build(int l,int r,int rt)
	{
		v[rt]= {0,0,1};
		if(l==r)return;
		int m=l+r>>1;
		build(l,m,rt<<1);
		build(m+1,r,rt<<1|1);
	}
	void push_down(int rt,ll ln,ll rn)
	{
		v[rt<<1]= {v[rt<<1].sum*v[rt].mul+v[rt].add*ln,v[rt<<1].add*v[rt].mul+v[rt].add,v[rt<<1].mul*v[rt].mul};
		v[rt<<1|1]= {v[rt<<1|1].sum*v[rt].mul+v[rt].add*rn,v[rt].mul*v[rt<<1|1].add+v[rt].add,v[rt<<1|1].mul*v[rt].mul};
		v[rt]= {v[rt].sum,0,1};
	}
	void add(int L,int R,ll C,int l,int r,int rt)
	{
		if(L<=l&&r<=R)
		{
			v[rt].add+=C;
			v[rt].sum+=C*(r-l+1);
			return;
		}
		int m=(l+r)/2;
		push_down(rt,m-l+1,r-m);
		if(L<=m)add(L,R,C,l,m,rt<<1);
		if(R>m)add(L,R,C,m+1,r,rt<<1|1);
		v[rt].sum=v[rt<<1].sum+v[rt<<1|1].sum;
	}
	void mul(int L,int R,ll C,int l,int r,int rt)
	{
		if(L<=l&&r<=R)
		{
			v[rt].mul*=C;
			v[rt].add*=C;
			v[rt].sum*=C;
			return;
		}
		int m=l+r>>1;
		push_down(rt,m-l+1,r-m);
		if(L<=m)mul(L,R,C,l,m,rt<<1);
		if(R>m)mul(L,R,C,m+1,r,rt<<1|1);
		v[rt].sum=v[rt<<1].sum+v[rt<<1|1].sum;
	}
	ll ask(int L,int R,int l,int r,int rt)
	{
		if(L<=l&&r<=R)return v[rt].sum;
		int m=l+r>>1;
		push_down(rt,m-l+1,r-m);
		ll ans=0;
		if(L<=m)ans+=ask(L,R,l,m,rt<<1);
		if(R>m)ans+=ask(L,R,m+1,r,rt<<1|1);
		return ans;
	}
};
struct Graph
{
	struct Vertex
	{
		vector<int> a,b;//相关出边和入边编号
		int siz,dep,top,dfn;//树链剖分中使用,依次代表子树节点数、深度、所在链的顶端节点、dfs序
	};
	struct Edge
	{
		int from,to;
		//ll dist,cap;//边长、容量,图论算法使用
	};
	vector<Vertex> v;//点集
	vector<Edge> e;//边集
	Graph(int n):v(n) {}
	void add(const Edge &ed)
	{
		//if(ed.from==ed.to)return;//如果有需要请拆点
		v[ed.from].a.push_back(e.size());
		v[ed.to].b.push_back(e.size());
		e.push_back(ed);
	}
};
struct Tree:Graph
{
	Tree(int n):Graph(n) {}
	int fa(int k,int i=0)
	{
		return e[v[k].b[i]].from;
	}
	int ch(int k,int i=0)
	{
		return e[v[k].a[i]].to;
	}
	void build(int u,const Graph &g)//无向图dfs建树,且重边在最前,u为根节点
	{
		v[u].siz=1;
		for(int i=0,w,k; i!=g.v[u].a.size(); ++i)
			if(k=g.v[u].a[i],w=g.e[k].to,!v[w].siz)//没访问过的点siz默认0
			{
				build(w,g);
				v[u].siz+=v[w].siz;
				add(g.e[k]);
				if(v[ch(u)].siz<v[w].siz)//重边移到最前
					swap(v[u].a.front(),v[u].a.back());
			}
	}
};
struct Diagram:Tree
{
	SegmentTree data;
	Diagram(const Graph &g,int root):
		Tree(g.v.size()),data(g.v.size())
	{
		build(root,g);
		int cnt=v[root].dfn=v[root].dep=1;
		dfs(v[root].top=root,cnt);
	}
	void dfs(int u,int &cnt)
	{
		for(int i=0,w; i!=v[u].a.size(); ++i)
		{
			v[w=ch(u,i)].dfn=++cnt;
			v[w].top=i?w:v[u].top;
			v[w].dep=v[u].dep+1;
			dfs(w,cnt);
		}
	}
	ll ask(int x,int y)
	{
		ll ans=0;
		for(; v[x].top!=v[y].top; x=fa(v[x].top))
		{
			if(v[v[x].top].dep<v[v[y].top].dep)swap(x,y);
			ans+=data.ask(v[v[x].top].dfn,v[x].dfn,1,v.size(),1);
		}
		if(v[x].dep<v[y].dep)swap(x,y);
		return ans+=data.ask(v[y].dfn,v[x].dfn,1,v.size(),1);
	}
	void add(int x,int y,ll pv)
	{
		for(; v[x].top!=v[y].top; x=fa(v[x].top))
		{
			if(v[v[x].top].dep<v[v[y].top].dep)swap(x,y);
			data.add(v[v[x].top].dfn,v[x].dfn,pv,1,v.size(),1);
		}
		if(v[x].dep<v[y].dep)swap(x,y);
		data.add(v[y].dfn,v[x].dfn,pv,1,v.size(),1);
	}
	void mul(int x,int y,ll pv)
	{
		for(; v[x].top!=v[y].top; x=fa(v[x].top))
		{
			if(v[v[x].top].dep<v[v[y].top].dep)swap(x,y);
			data.mul(v[v[x].top].dfn,v[x].dfn,pv,1,v.size(),1);
		}
		if(v[x].dep<v[y].dep)swap(x,y);
		data.mul(v[y].dfn,v[x].dfn,pv,1,v.size(),1);
	}
};
int main()
{
	for(int n; ~scanf("%d",&n);)
	{
		Graph g(n+1);
		for(int i=2,b; i<=n; ++i)
			scanf("%d",&b),g.add({b,i});
		Diagram d(g,1);
		scanf("%d",&n);
		for(int i=0,u,v; i<n; ++i)
		{
			ll x;
			scanf("%llu%d%d",&x,&u,&v);
			if(x==1)scanf("%llu",&x),d.mul(u,v,x);
			else if(x==2)scanf("%llu",&x),d.add(u,v,x);
			else if(x==3)d.mul(u,v,-1),d.add(u,v,-1);
			else printf("%llu\n",d.ask(u,v));
		}
	}
}

Modular Production Line

#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll N=100009,NPOS=-1,INF=1e18;
struct Ranker:vector<ll>
{
	void init()
	{
		sort(begin(),end()),resize(unique(begin(),end())-begin());
	}
	int ask(ll x)const
	{
		return lower_bound(begin(),end(),x)-begin();
	}
};
struct Graph
{
	struct Vertex
	{
		vector<int> a/*,b*/;//相关出边和入边编号
		//int siz,dep,top,dfn;//树链剖分中使用,依次代表子树节点数、深度、所在链的顶端节点、dfs序
	};
	struct Edge
	{
		int from,to;
		ll dist,cap;//边长、容量,图论算法使用
	};
	vector<Vertex> v;//点集
	vector<Edge> e;//边集
	Graph(int n):v(n) {}
	void add(const Edge &ed)
	{
		if(ed.from==ed.to)return;//如果有需要请拆点
		v[ed.from].a.push_back(e.size());
		//v[ed.to].b.push_back(e.size());
		e.push_back(ed);
	}
};
struct EdmondKarp:Graph
{
	ll flow,cost;
	vector<ll> f;
	EdmondKarp(int n):Graph(n) {}
	void add(Edge ed)
	{
		Graph::add(ed);
		swap(ed.from,ed.to),ed.cap=0,ed.dist*=-1;
		Graph::add(ed);
	}
	void ask(int s,int t)
	{
		vector<int> p(v.size(),NPOS);
		for(f.assign(e.size(),flow=cost=0);;)
		{
			vector<ll> d(v.size(),INF);
			vector<int> flag(v.size(),d[s]=0);
			for(deque<int> q(flag[s]=1,s); !q.empty(); q.pop_front())
				for(int u=q.front(),i=flag[u]=0,k,to; i<v[u].a.size(); ++i)
					if(k=v[u].a[i],to=e[k].to,
					        e[k].cap>f[k]&&d[to]>d[u]+e[k].dist)
					{
						d[to]=d[u]+e[k].dist,p[to]=k;
						if(!flag[to])q.push_back(to),flag[to]=1;
					}
			if(d[t]==INF)return;
			ll _f=INF;
			for(int u=t; u!=s; u=e[p[u]].from)
				_f=min(_f,e[p[u]].cap-f[p[u]]);
			for(int u=t; u!=s; u=e[p[u]].from)
				cost+=_f*e[p[u]].dist,f[p[u]]+=_f,f[p[u]^1]-=_f;
			flow+=_f;
		}
	}
};
int t,n,m,k,x[N],y[N],w[N];
int main()
{
	for(scanf("%d",&t); t--;)
	{
		Ranker rk;
		scanf("%d%d%d",&n,&k,&m);
		for(int i=0; i<m; ++i)
		{
			scanf("%d%d%d",&x[i],&y[i],&w[i]);
			rk.push_back(x[i]);
			rk.push_back(++y[i]);
		}
		rk.init();
		EdmondKarp g(rk.size()+2);
		for(int i=0; i<rk.size(); ++i)g.add({i,i+1,0,k});
		for(int i=0; i<m; ++i)g.add({rk.ask(x[i]),rk.ask(y[i]),-w[i],1});
		g.add({rk.size()+1,0,0,k});
		g.ask(rk.size()+1,rk.size());
		printf("%lld\n",-g.cost);
	}
}

Give Candies

答案是 2 n 2 2^{n-2} ,用费马小定理把指数对M-1取模后进行运算避免更多的高精度运算。

#include<stdio.h>
#define mul(a,b,c) (1LL*(a)*(b)%(c))
typedef int ll;
const ll M=1e9+7;
ll pow(ll a,ll b,ll m)
{
	ll r=1;
	for(a%=m; b; b>>=1,a=mul(a,a,m))
		if(b&1)r=mul(r,a,m);
	return r;
}
char s[100009];
int t,n;
int main()
{
	for(scanf("%d",&t); t--;)
	{
		scanf("%s",s);
		for(int i=n=0; s[i]; ++i)
			n=mul(n,10,M-1)+s[i]-'0';
		printf("%d\n",pow(2,n+M-2,M));
	}
}

String and Times

拉一个后缀数组的板子跑掉了。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
struct SufArr
{
	vector<int> sa,rk,h;
	SufArr(const vector<int> &s,int m):sa(s.size(),0),rk(s),h(s.size(),0)
	{
		vector<int> cnt(s.size()+m,0);
		for(int i=0; i<s.size(); ++i)++cnt[rk[i]];
		for(int i=1; i<m; ++i)cnt[i]+=cnt[i-1];
		for(int i=0; i<s.size(); ++i)sa[--cnt[rk[i]]]=i;
		for(int k=1,j=0; k<=s.size()&&j<s.size()-1; k<<=1)
		{
			for(int i=0; i<s.size(); ++i)
			{
				if(j=sa[i]-k,j<0)j+=s.size();
				h[cnt[rk[j]]++]=j;
			}
			cnt[0]=sa[h[0]]=j=0;
			for(int i=1; i<s.size(); ++i)
			{
				if(rk[h[i]]!=rk[h[i-1]]||rk[h[i]+k]!=rk[h[i-1]+k])
					cnt[++j]=i;
				sa[h[i]]=j;
			}
			swap(rk,sa),swap(sa,h);
		}
		for(int i=0,k=0,j=rk[0]; i<s.size()-1; ++i,++k)
			for(; ~k&&s[i]!=s[sa[j-1]+k]; j=rk[sa[j]+1],--k)
				h[j]=k;
	}
};
struct SparseTable
{
	typedef int ll;
	vector<vector<ll> > f;
	SparseTable(const vector<ll> &a):f(log2(a.size())+1,a)
	{
		for(int k=0; k+1<f.size(); ++k)
			for(int i=0; i+(1<<k)<a.size(); ++i)
				f[k+1][i]=min(f[k][i],f[k][i+(1<<k)]);
	}
	ll ask(int l,int r)
	{
		int k=log2(r-l+1);
		return min(f[k][l],f[k][r+1-(1<<k)]);
	}
};
ll cal(SufArr &sa,SparseTable &st,int k)//原串中至少出现k次的子串数量
{
	ll ans=0;
	if(k>1)
		for(int l=2,r=k; r<sa.h.size(); ++l,++r)
			ans+=max(st.ask(l,r)-sa.h[l-1],0);
	else
		for(int i=1; i<sa.h.size(); ++i)
			ans+=sa.h.size()-1-sa.sa[i]-sa.h[i];
	return ans;
}
char s[2000009];
int main()
{
	for(int a,b; ~scanf("%s%d%d",s,&a,&b);)
	{
		SufArr sa(vector<int>(s,s+strlen(s)+1),'Z'+1);
		SparseTable st(sa.h);
		printf("%lld\n",cal(sa,st,a)-cal(sa,st,b+1));
	}
}

Save the Room

#include<stdio.h>
int main()
{
	for(int a,b,c; ~scanf("%d%d%d",&a,&b,&c);)
		printf(a%2&&b%2&&c%2?"No\n":"Yes\n");
}

Participate in E-sports

交了个高精度开根号上去。

#include<cmath>
#include<iostream>
#include<vector>
using namespace std;
typedef long long ll;
struct Wint:vector<int>//继承vector
{
	static const int width=9,base=1e9;
	Wint(unsigned long long n=0)//普通初始化,当整型数和Wint同时运算时会提升至Wint
	{
		for(; n; n/=base)push_back(n%base);
	}
	explicit Wint(const string &s)//字符串初始化函数,未判断字符串合法情况
	{
		for(int len=int(s.size()-1)/width+1,b,e,i=0; i!=len; ++i)
			for(e=s.size()-i*width,b=max(0,e-width),push_back(0); b!=e; ++b)
				back()=back()*10+s[b]-'0';
		trim(0);
	}
	Wint& trim(bool up=1)//去前导0,是否需要进位,很常用的小函数,为方便返回自身
	{
		for(int i=1; up&&i<size(); ++i)
		{
			if(at(i-1)<0)--at(i),at(i-1)+=base;
			if(at(i-1)>=base)at(i)+=at(i-1)/base,at(i-1)%=base;
		}
		while(!empty()&&back()<=0)pop_back();
		for(; up&&!empty()&&back()>=base; at(size()-2)%=base)
			push_back(back()/base);
		return *this;
	}
};
istream& operator>>(istream &is,Wint &n)
{
    string s;//懒
    return is>>s,n=Wint(s),is;
}
bool operator<(const Wint &a,const Wint &b)
{
    if(a.size()!=b.size())return a.size()<b.size();
    for(int i=a.size()-1; ~i; --i)
        if(a[i]!=b[i])return a[i]<b[i];
    return 0;
}
bool operator>(const Wint &a,const Wint &b)
{
    return b<a;
}
bool operator<=(const Wint &a,const Wint &b)
{
    return !(a>b);
}
bool operator>=(const Wint &a,const Wint &b)
{
    return !(a<b);
}
Wint& operator+=(Wint &a,const Wint &b)
{
    a.resize(max(a.size(),b.size()));//保证有足够的位数
    for(int i=0; i!=b.size(); ++i)a[i]+=b[i];
    return a.trim();//单独进位防自运算
}
Wint operator+(Wint a,const Wint &b)
{
    return a+=b;
}
Wint& operator++(Wint &a)//前置版本
{
    return a+=1;//懒
}
Wint operator++(Wint &a,int)//后置版本
{
    Wint b=a;
    return ++a,b;
}
Wint& operator-=(Wint &a,const Wint &b)//a<b会使a变为0
{
    a.resize(max(a.size(),b.size()));//保证有足够的位数
    for(int i=0; i!=b.size(); ++i)a[i]-=b[i];
    return a.trim();//单独进位防自运算
}
Wint operator-(Wint a,const Wint &b)
{
    return a-=b;
}
Wint& operator--(Wint &a)//前置版本
{
    return a-=1;//懒
}
Wint operator--(Wint &a,int)//后置版本
{
    Wint b=a;
    return --a,b;
}
Wint& operator*=(Wint &a,const Wint &b)
{
    vector<unsigned long long> n(a.size()+b.size()+2,0);//防爆int,多开位用于进位
    for(int j=0; j!=b.size(); ++j)
        if(b[j])//稀疏优化,特殊情况很有效
            for(int i=0; i!=a.size(); ++i)
                n[i+j]+=(unsigned long long)a[i]*b[j];
    for(int i=1; i<n.size(); ++i)//这里用<防止位数0,单独进位防自运算
        n[i]+=n[i-1]/a.base,n[i-1]%=a.base;
    while(!n.empty()&&!n.back())n.pop_back();
    return a.assign(n.begin(),n.end()),a;
}
Wint operator*(Wint a,const Wint &b)
{
    return a*=b;
}
Wint& operator/=(Wint &a,Wint b)
{
    Wint r,c,d=b.base/(b.back()+1);
    a*=d,b*=d,c.assign(a.size(),0);
    for(int i=a.size()-1; ~i; --i)
    {
        r.insert(r.begin(),a[i]);
        unsigned long long s=0;
        for(int j=b.size(); j+1>=b.size(); --j)//b.size()==0肯定第一行就出问题的
            s=s*b.base+(j<r.size()?r[j]:0);
        for(d=c[i]=s/b.back(),d*=b; r<d; r+=b)--c[i];
        r-=d;
    }
    return swap(a,c),a.trim(0);//r为加倍后的余数,可通过高精度除低精度得到真正余数,此处略
}
Wint operator/(Wint a,const Wint &b)
{
    return a/=b;
}
Wint& operator%=(Wint &a,const Wint &b)
{
    return a-=a/b*b;
}
Wint operator%(Wint a,const Wint &b)
{
    return a%=b;
}
bool cmp(const Wint &a,ll c,int d,const Wint &b)
{
    ll l=-(a.base<<1),t=0;
    if(b.size()<a.size()+d&&c)return 1;
    for(int i=b.size()-1; l<=t&&t<=0&&i>d; --i)
        t=t*a.base+c*(i-d-1<a.size()?a[i-d-1]:0)-b[i];
    for(int i=d-1; l<=t&&t<=0&&~i; --i)
        t=t*a.base-b[i];
    return t>0;
}
void sub(Wint &a,const Wint &b,ll k,int d)
{
    int l=b.size()+d;
    for(int i=d+1; i<=l; ++i)
    {
        ll tmp=a[i]-k*b[i-d-1];
        if(tmp<0)
        {
            a[i+1]+=(tmp-a.base+1)/a.base;
            a[i]=tmp-(tmp-a.base+1)/a.base*a.base;
        }
        else a[i]=tmp;
    }
    for(int i=l+1; i<a.size()&&a[i]<0; ++i)
    {
        a[i+1]+=(a[i]-a.base+1)/a.base;
        a[i]-=(a[i]-a.base+1)/a.base*a.base;
    }
    a.trim(0);
}
Wint sqrt(Wint a)
{
    Wint ret;
    ret.assign((a.size()+1)>>1,0);
    for(int i=ret.size()-1; ~i; --i)
    {
        int l=0,r=a.base,m=ret[i]=(l+r)>>1;
        while(r-l>1)
        {
            if(cmp(ret,m,i-1,a))r=m;
            else l=m;
            m=ret[i]=(l+r)>>1;
        }
        sub(a,ret,m,i-1);
        ret[i]+=m;
    }
    ret.trim(0);
    for(int i=0; i<ret.size(); ++i)ret[i]>>=1;
    return ret;
}
int check(Wint n)
{
	Wint sn=sqrt(n);
	return sn*sn==n||(sn-1)*(sn-1)==n||(sn+1)*(sn+1)==n;
}
int main()
{
	int t;
	for(cin>>t; t--;)
	{
		Wint n,m;
		cin>>n,m=n*(n-1)/2;
		int ans=check(n)*2+check(n*(n-1)/2);
		cout<<(ans==0?"League of Legends\n":
		       ans==1?"Clash Royale\n":
		       ans==2?"Hearth Stone\n":
		       "Arena of Valor\n");
	}
}

Transport Ship

拆成01背包。

#include<stdio.h>
#include<string.h>
const int N=511,S=32767>>1,M=1e9+7;
int t,n,q,m,v[N],f[N][S];
int main()
{
	for(scanf("%d",&t); t--;)
	{
		scanf("%d%d",&n,&q);
		for(int i=m=0,V,C; i<n; ++i)
		{
			scanf("%d%d",&V,&C);
			for(int i=0; i<C; ++i)
				v[++m]=(1<<i)*V;
		}
		for(int i=f[0][0]=1; i<=m; ++i)
			for(int s=0; s<S; ++s)
				if(f[i][s]=f[i-1][s],s>=v[i])
					f[i][s]=(f[i][s]+f[i-1][s-v[i]])%M;
		for(int i=0,s; i<q; ++i)
		{
			scanf("%d",&s);
			printf("%d\n",f[m][s]);
		}
	}
}

Poor God Water

矩阵乘一下。

#include<cstdio>
#include<algorithm>
#define mul(a,b,c) (1LL*(a)*(b)%(c))
using namespace std;
typedef long long ll;
const ll N=9,M=1e9+7;
struct Matrix
{
	static int n;
	ll a[N][N];
	Matrix(ll k=0)
	{
		for(int i=0; i<n; ++i)fill(a[i],a[i]+n,0),a[i][i]=k;
	}
	ll* operator[](int n)
	{
		return a[n];
	}
};
int Matrix::n=N;
Matrix operator*(const Matrix &a,const Matrix &b)
{
	Matrix r(0);
	for(int i=0; i<r.n; ++i)
		for(int j=0; j<r.n; ++j)
			for(int k=0; k<r.n; ++k)
				r.a[i][j]=(r.a[i][j]+mul(a.a[i][k],b.a[k][j],M))%M;
	return r;
}
Matrix pow(Matrix a,ll b)
{
	Matrix r(1);
	for(; b; b>>=1,a=a*a)
		if(b&1)r=r*a;
	return r;
}
int main()
{
	ll t,n,ans;
	for(scanf("%lld",&t); t--;)
	{
		scanf("%lld",&n);
		if(n<3)
		{
			printf("%d\n",n==1?3:9);
			continue;
		}
		Matrix A,P;
		for(int i=0; i<N; ++i)A[i][0]=1;
		P[0][3]=P[0][6]=1;
		P[1][0]=P[1][3]=P[1][6]=1;
		P[2][0]=P[2][3]=1;
		P[3][1]=P[3][4]=P[3][7]=1;
		P[4][1]=P[4][7]=1;
		P[5][1]=P[5][4]=1;
		P[6][5]=P[6][8]=1;
		P[7][2]=P[7][8]=1;
		P[8][2]=P[8][5]=1;
		A=pow(P,n-2)*A;
		for(int i=ans=0; i<N; ++i)ans=(ans+A[i][0])%M;
		printf("%lld\n",ans);
	}
}

猜你喜欢

转载自blog.csdn.net/w_weilan/article/details/82768705