问题 G: 强
时间限制: 1 Sec 内存限制: 128 MB
[提交] [状态]
题目描述
Lh:粉兔你教我一下抽屉原理吧
Clz:就是给你一个长度为 n 的序列,每个数只能取 0,1,2,那你连续取三个数必然有两个相等……
Lh:等等你梭啥,再说一遍
Clz:……emmm 当我没说
Marser:就是一个序列,对于每一个连续三元组都要满足其中至少有两个相等
现在粉兔问你:有多少个长度为 n 的序列满足粉兔的要求?请对 19260817 取模。
输入
一行一个正整数n(3≤n≤1018)。
输出
一行一个整数,含义如题。
样例输入 Copy
4
样例输出 Copy
51
提示
51 种序列如下:
[0,0,0,0],[0,0,0,1],[0,0,0,2],[0,0,1,0],[0,0,1,1],[0,0,2,0],[0,0,2,2],[0,1,0,0],[0,1,0,1],[0,1,1,0],[0,1,1,1],[0,1,1,2],[0,2,0,0],[0,2,0,2],[0,2,2,0],[0,2,2,1],[0,2,2,2],[1,0,0,0],[1,0,0,1],[1,0,0,2],[1,0,1,0],[1,0,1,1],[1,1,0,0],[1,1,0,1],[1,1,1,0],[1,1,1,1],[1,1,1,2],[1,1,2,1],[1,1,2,2],[1,2,1,1],[1,2,1,2],[1,2,2,0],[1,2,2,1],[1,2,2,2],[2,0,0,0],[2,0,0,1],[2,0,0,2],[2,0,2,0],[2,0,2,2],[2,1,1,0],[2,1,1,1],[2,1,1,2],[2,1,2,1],[2,1,2,2],[2,2,0,0],[2,2,0,2],[2,2,1,1],[2,2,1,2],[2,2,2,0],[2,2,2,1],[2,2,2,2]。
思路:矩阵快速幂
#include <map> #include <queue> #include <string> #include<iostream> #include<stdio.h> #include<string.h> #include <algorithm> #include <math.h> typedef long long ll; using namespace std; const int maxn=2e5+1010; #define inf 0x3f3f3f3f #define sf scanf #define pf printf const int mod=19260817; const int MOD=10007; inline int read() { int x=0; bool t=false; char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } priority_queue<ll , vector<ll> , greater<ll> > mn;//上 小根堆 小到大 priority_queue<ll , vector<ll> , less<ll> > mx;//下 大根堆 大到小 //map<ll,ll>mp; ll n,m,t,l,r,p; ll sum,ans,res,cnt,flag; struct Mat { ll m[101][101]; };//存储结构体 Mat a,e; //a是输入的矩阵,e是输出的矩阵 Mat Mul(Mat x,Mat y) { Mat c; for(int i=1;i<=n;++i){ for(int j=1;j<=n;++j){ c.m[i][j] = 0; } } for(int i=1;i<=n;++i){ for(int j=1;j<=n;++j){ for(int k=1;k<=n;++k){ c.m[i][j] = c.m[i][j]%mod + x.m[i][k]*y.m[k][j]%mod; } } } return c; } Mat pow(Mat x,ll y)//矩阵快速幂 { Mat ans; for(int i=1;i<=n;i++){ ans.m[i][i]=1; } while(y){ if(y&1) ans = Mul(ans,x); x = Mul(x,x); y>>=1; } return ans; } int main() { sf("%lld",&m); a.m[1][1]=2; a.m[1][2]=1; a.m[2][1]=1; a.m[2][2]=0; n=2; e=pow(a,m-1); cout<<(e.m[1][1]+e.m[1][2])*3%mod<<endl; /* [0,0,0,0],[0,0,0,1],[0,0,0,2],[0,0,1,0],[0,0,1,1], [0,0,2,0],[0,0,2,2],[0,1,0,0],[0,1,0,1],[0,1,1,0], [0,1,1,1],[0,1,1,2],[0,2,0,0],[0,2,0,2],[0,2,2,0], [0,2,2,1],[0,2,2,2], [1,0,0,0],[1,0,0,1],[1,0,0,2],[1,0,1,0],[1,0,1,1], [1,1,0,0],[1,1,0,1],[1,1,1,0],[1,1,1,1],[1,1,1,2], [1,1,2,1],[1,1,2,2],[1,2,1,1],[1,2,1,2],[1,2,2,0], [1,2,2,1],[1,2,2,2], [2,0,0,0],[2,0,0,1],[2,0,0,2],[2,0,2,0],[2,0,2,2], [2,1,1,0],[2,1,1,1],[2,1,1,2],[2,1,2,1],[2,1,2,2], [2,2,0,0],[2,2,0,2],[2,2,1,1],[2,2,1,2],[2,2,2,0], [2,2,2,1],[2,2,2,2]。*/ return 0; }
推这个东西的过程可以和大家分享一下
其实也没什么 就是用计算机跑for循环 毕竟计算机算大数据时比我算的快而准。
最后得到一组数 21 51 123 197....
都是 3的倍数除以三得到
7 17 41 99 ....
可以得到 an=2*an-1+an-2;
当时忘了怎么用矩阵快速幂了(也就是不会,嘻嘻~~)。
这样我们就可以构造了。我也不太懂是怎么构造的 ,这个简单 还是巧了我一下凑出来了,就是
2 1 1 0
这样身下的就简单了。
#include <map> #include <queue> #include <string> #include<iostream> #include<stdio.h> #include<string.h> #include <algorithm> #include <math.h> typedef long long ll; using namespace std; const int maxn=2e5+1010; #define inf 0x3f3f3f3f #define sf scanf #define pf printf const int mod=19260817; const int MOD=10007; inline int read() { int x=0; bool t=false; char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } priority_queue<ll , vector<ll> , greater<ll> > mn;//上 小根堆 小到大 priority_queue<ll , vector<ll> , less<ll> > mx;//下 大根堆 大到小 //map<ll,ll>mp; ll n,m,t,l,r,p; ll sum,ans,res,cnt,flag; ll a[maxn]; int main (){ for(int o=1;o<=3;o++) for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) { for(int k=1;k<=3;k++) for(int h=1;h<=3;h++) for(int y=1;y<=3;y++) if((o!=i&&o!=j&&i!=j)||(i!=j&&i!=k&&j!=k)||(j!=k&&j!=h&&h!=k)||(k!=h&&h!=y&&k!=y))continue; else a[++cnt]=i*10000+j*1000+k*100+h*10+y+o*100000; } sort(a+1,a+1+cnt); cout<<cnt<<endl<<endl; for(int i=1;i<=cnt;i++) { cout<<a[i]<<" "; if(i%5==0) cout<<endl; } return 0; } /* 111 112 113 121 122 131 133 211 212 221 222 223 232 233 311 313 322 323 331 332 333 */