B.generator 1(矩阵快速幂)
•题意
已知 $f_{i}=af_{i-1}+bf_{i-2}$;
输入 f0,f1,a,b,n,mod;
求 fn%mod ;
•思路
首先将递推式转化为矩阵乘法表达式:
$left( egin{array}{cc} f_{i} \ f_{i-1} end{array} ight)=left( egin{array}{cc} a&b \ 1&0 end{array} ight)cdotleft( egin{array}{cc} f_{i-1} \ f_{i-2} end{array} ight)$
不妨令 $mathbf{A_{i}} =left( egin{array}{cc} f_{i} \ f_{i-1} end{array} ight)$ , $mathbf{T} =left( egin{array}{cc} a&b \ 1&0 end{array} ight)$;
那么,原式可化为 $A_{i}=Tcdot A_{i-1}=T^{2}cdot A_{i-2}= cdots = T^{i-1}cdot A_{1}$;
还差最后一步,如何处理 $T^{n-1}$ ?
n 很大很大很大;
考虑到秦九韶算法,将 n 分解;
假设 n-1 = 3194;
那么 n 可分解为 $n=igg(Big(ig((3 imes 10)+1ig) imes 10+9Big) imes 10+4igg)$;
在计算 $T^{3194}$ 时,可以按照字符串的位数进行处理;
先计算 ans = T3;
ans = ans10·T1;(ans=T31)
ans = ans10·T9;(ans = T319)
ans = ans10·T4;(ans = T3194)
•代码
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 ll xx,yy,a,b; 5 ll n,mod; 6 char s[10000005]; 7 struct matrix 8 { 9 ll m[2][2]; 10 matrix() 11 { 12 memset(m,0,sizeof(m)); 13 } 14 void Init() 15 { 16 for(int i=0;i<2;++i) 17 m[i][i]=1; 18 } 19 }; 20 21 matrix mul(matrix a,matrix b) 22 { 23 matrix c; 24 for(int i=0;i<2;i++) 25 for(int j=0;j<2;j++) 26 for(int k=0;k<2;k++) 27 c.m[i][j]=(c.m[i][j]+(a.m[i][k]*b.m[k][j])%mod)%mod; 28 return c; 29 } 30 31 32 matrix qpow_matrix(matrix a,ll b) 33 { 34 matrix res; 35 res.Init(); 36 while(b) 37 { 38 if(b&1) 39 res=mul(res,a); 40 a=mul(a,a); 41 b>>=1; 42 } 43 return res; 44 } 45 46 47 int main() 48 { 49 cin>>xx>>yy>>a>>b>>s>>mod; 50 matrix t,a1; 51 t.m[0][0]=a,t.m[0][1]=b; 52 t.m[1][0]=1,t.m[1][1]=0; 53 a1.m[0][0]=yy,a1.m[0][1]=0; 54 a1.m[1][0]=xx,a1.m[1][1]=0; 55 int len=strlen(s); 56 57 for(int i=len-1;i>=0;i--) 58 { 59 if(s[i]>'0') 60 { 61 s[i]--; 62 for(int j=i+1;j<=len-1;j++) 63 s[j]='9'; 64 break; 65 } 66 } 67 68 matrix ans,tt; 69 ans.m[0][0]=1,ans.m[1][1]=1; 70 for(int i=0;i<len;i++) 71 { 72 int num=s[i]-'0'; 73 ans=qpow_matrix(ans,10); 74 // cout<<"num:"<<num<<endl; 75 if(num==0) 76 continue; 77 tt=qpow_matrix(t,num); 78 ans=mul(ans,tt); 79 } 80 matrix an=mul(ans,a1); 81 cout<<an.m[0][0]<<endl; 82 }
H.subsequence 2(拓扑排序)
•题意
有一个长度为n的小写字母字符串,
现给你m*(m-1)/2条信息
每一条信息包含两个可以显示的字母
接着根据顺序显示此字符串里的这两个字母
问是否存在,如果存在输出
•思路
可以给每个字母标一个序号,
根据字母的先后顺序连边建图
例如
abbcacbac
9 3 标号 连边建图
ab 6
abbaba 分别标号为1 2 3 4 5 6 1->2,2->3,3->4,4->5,5->6
ac 6
acacac 其中c标号为7 8 9,因为a已经被标号 1->7,7->4,4->8,8->6,6->9
bc 6
bbccbc bc都已经被标号 2->3,3->7,7->8,8->5,5->9
然后利用拓扑排序看是否可以组成存在且唯一的序列
•代码
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 const int maxn=1e5+5; 5 queue<int> q; 6 vector<int> v[maxn]; 7 vector<int> p[27]; //p[i]存第i字母的所有标号 8 int Indu[maxn];//入度 9 char s[maxn]; 10 int cnt=0; 11 bool vis[27]; 12 int a[27];//a[i]=j即第i个字母的第j个标号 13 map<int,char> mp; 14 int n,m; 15 16 bool topsort() 17 { 18 while(!q.empty()) 19 q.pop(); 20 21 int num=0; 22 for(int i=1;i<=cnt;i++) 23 if(!Indu[i]) 24 q.push(i); 25 26 while(!q.empty()) 27 { 28 int now=q.front(); 29 q.pop(); 30 num++; 31 32 s[num]=mp[now]; 33 for(int i=0;i<v[now].size();i++) 34 { 35 if(--Indu[v[now][i]]==0) 36 q.push(v[now][i]); 37 } 38 } 39 if(num==n) 40 return true; 41 else 42 return false; 43 } 44 45 46 int main() 47 { 48 cin>>n>>m; 49 for(int k=1;k<=m*(m-1)/2;k++) 50 { 51 char ch[2]; 52 int len; 53 scanf("%s%d",ch,&len); 54 if(len==0) 55 continue; 56 scanf("%s",s+1); 57 for(int i=1;i<=len;i++) 58 { 59 int cur=s[i]-'a'; 60 if(vis[cur])//没标过号的才标号 61 continue; 62 cnt++; 63 64 p[cur].push_back(cnt); 65 mp[cnt]=s[i];//标号与字母映射 66 } 67 68 vis[ch[0]-'a']=1; 69 vis[ch[1]-'a']=1; 70 71 a[ch[0]-'a']=0;//连边关系从头开始 72 a[ch[1]-'a']=0; 73 74 for(int i=1;i<len;i++) 75 { 76 int uu=s[i]-'a'; 77 int vv=s[i+1]-'a'; 78 79 if(a[uu]==p[uu].size()) 80 { 81 puts("-1"); 82 return 0; 83 } 84 a[uu]++; 85 if(a[vv]==p[vv].size()) 86 { 87 puts("-1"); 88 return 0; 89 } 90 v[p[uu][a[uu]-1]].push_back(p[vv][a[vv]]); 91 Indu[p[vv][a[vv]]]++; 92 } 93 } 94 if(topsort()) 95 { 96 for(int i=1;i<=n;i++) 97 cout<<s[i]; 98 } 99 else 100 { 101 puts("-1"); 102 return 0; 103 } 104 }