题目链接:
http://sustoj.com/JudgeOnline/contest.php?cid=1090
A: 最长回文串
马拉车 裸题,
但因为数据很水,所以暴力也是可以过的
下面简单介绍一下马拉车算法
回文分为偶回文(abba)和奇回文(abcba)。在处理奇偶回文之间有差异,所以用到了一个技巧
在 (每个字符之间和开头) 插入一个无关的字符,
比如说: abbahopxpo 转换为 $#a#b#b#a#h#o#p#x#p#o# ('$' 是防止越界)
起初有一个偶回文abba和一个奇回文opxpo,被转换为#a#b#b#a#和#o#p#x#p#o#,长度都转换成了奇数。
回文半径数组radius
回文半径数组radius是用来记录以每个位置的字符为回文中心求出的回文半径长度,如下图所示
可以看出,radius[i] - 1正好是原字符串中最长回文串的长度。
求解回文半径数组radius
mx 代表以 id 为中心的最长回文的右边界,也就是mx = id + radius[id]。
如图,mx 到 mx 关于 id 对称点之间是一个回文串,
要是从 j 到 mx 的对称点 之间存在回文串,那么 i 到 mx 之间也一定会存在回文串
那么以 i 为对称点的回文串的长度最少是 min(radius[j],mx−i)
并且j=2∗id−i
所以最终优化的是 radius[i]=min(radius[2∗id−i],mx−i)
例题一
https://cn.vjudge.net/problem/HDU-3068
AC code
/*
最长回文
HDU - 3068
https://cn.vjudge.net/problem/HDU-3068
题面:最长回文长度
解法:马拉车算法
*/
#include <bits/stdc++.h>
using namespace std;
#define maxn 300005
int radius[maxn];
char s[maxn];
char s_new[maxn];
int init(){
int len=strlen(s);
s_new[0]='$';
s_new[1]='#';
int j=2;
for(int i=0;i<len;i++){
s_new[j++]=s[i];
s_new[j++]='#';
}
s_new[j]='\0';
return j;
}
int Manacher(){
int len=init();
int ans=-1;
int id;
int mx=0;
for(int i=1;i<len;i++){
if(i<mx) radius[i]=min(radius[2 * id - i], mx - i);
else radius[i]=1;
while(s_new[i-radius[i]]==s_new[i+radius[i]]){
radius[i]++;
}
if(mx<i+radius[i]){
id=i;
mx=i+radius[i];
}
ans=max(ans,radius[i]-1);
}
return ans;
}
int main(){
while(~scanf("%s", s)){
printf("%d\n", Manacher());
}
}
B: 小K的弹夹
原题是:
L. Poor God Water(ACM-ICPC 2018 焦作赛区网络预赛)
解法呢也很简单:矩阵快速幂
难点是能不能想到矩阵快速幂 和 怎么构造矩阵
构造矩阵
黄色的表示不可能出现的情况, 前两个中后面的必须等于后两个中前面
蓝色是规律(1)
红色是规律(2)
AC code
#include <bits/stdc++.h>
using namespace std;
#define MOD 1000000007
#define ll long long
struct matrix{//矩阵快速幂
ll m[9][9];
};
matrix matrix_multi(matrix a,matrix b){
matrix tmp;
for(int i=0;i<9;i++)
for(int j=0;j<9;j++){
tmp.m[i][j]=0;
for(int k=0;k<9;k++)
tmp.m[i][j]=((tmp.m[i][j])% (MOD) + (a.m[i][k]*b.m[k][j]+MOD)% (MOD)) % (MOD);
}
return tmp;
}
matrix matrix_pow(matrix a,matrix b,ll n){
while(n>0){
if(n&1) b=matrix_multi(a,b);
a=matrix_multi(a,a);
n>>=1;
}
return b;
}
int main(){
int T;
cin>>T;
ll n;
matrix a;
while(T--){
memset(a.m,0,sizeof a.m);
a.m[0][1]=a.m[0][2]=1;
a.m[1][3]=a.m[1][4]=1;
a.m[2][6]=a.m[2][7]=a.m[2][8]=1;
a.m[3][0]=a.m[3][2]=1;
a.m[4][3]=a.m[4][5]=1;
a.m[5][6]=a.m[5][8]=1;
a.m[6][0]=a.m[6][1]=a.m[6][2]=1;
a.m[7][4]=a.m[7][5]=1;
a.m[8][6]=a.m[8] [7]=1;
cin>>n;
if(n==2){
cout<<9<<endl;
continue;
}
if(n==1){
cout<<3<<endl;
continue;
}
matrix ans=matrix_pow(a,a,n-3);
ll num=0;
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
num=(num+ans.m[i][j])%MOD;
}
}
cout<<num<<endl;
}
return 0;
}
C: 费马小定理
原题是:
What day is that day?
先说费马小定理
如果 p p p是素数 , a a a 是正整数,且 G C D ( a , p ) = 1 GCD(a,p)= 1 GCD(a,p)=1 , 则 a p − 1 ≡ 1 ( m o d p ) a^{p-1} ≡ 1 (mod \ \ p) ap−1≡1(mod p)
N 为 任 意 数 , 所 以 N 可 以 等 于 N = 7 K 1 + m 1 其 中 K 1 ≥ 0 , 0 ≤ m 1 < 7 N为任意数,所以N可以等于 N=7K_1+m_1 其中 K_1≥0,0≤m_1<7 N为任意数,所以N可以等于N=7K1+m1其中K1≥0,0≤m1<7
N N % 7 = ( 7 K 1 + m 1 ) N % 7 = m 1 N % 7 N^N\%7=(7K_1+m_1)^N\%7=m_1^N\%7 NN%7=(7K1+m1)N%7=m1N%7
m 1 和 7 互 质 , 由 费 马 小 定 理 得 m 1 6 % 7 = 1 m_1和7互质,由费马小定理得 m_1^6\%7=1 m1和7互质,由费马小定理得m16%7=1
N 为 任 意 数 , 所 以 N 可 以 等 于 N = 6 K 2 + m 2 其 中 K 2 ≥ 0 , 0 ≤ m 2 < 6 N为任意数,所以N可以等于 N=6K_2+m_2 其中 K_2≥0,0≤m_2<6 N为任意数,所以N可以等于N=6K2+m2其中K2≥0,0≤m2<6
m 1 N % 7 = m 1 ( 6 K 2 + m 2 ) % 7 = m 1 m 2 % 7 m_1^N\%7=m_1^{(6K_2+m_2)}\%7=m_1^{m_2}\%7 m1N%7=m1(6K2+m2)%7=m1m2%7
由 于 0 ≤ m 1 < 7 , 0 ≤ m 2 < 6 因 此 可 知 有 7 ∗ 6 = 42 种 情 况 会 循 环 出 现 由于0≤m_1<7, 0≤m_2<6 因此可知有7*6=42种情况会循环出现 由于0≤m1<7,0≤m2<6因此可知有7∗6=42种情况会循环出现
但 每 42 个 数 后 他 们 得 起 始 数 字 会 发 生 改 变 , 所 以 总 循 环 数 为 7 ∗ 42 = 294 但每42个数后他们得起始数字会发生改变,所以总循环数为7*42=294 但每42个数后他们得起始数字会发生改变,所以总循环数为7∗42=294
AC code
先暴力跑前500个,然后打表
有些人可能直接就能从表里直接发现到规律
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
using namespace std;
char c[8][10]={"Saturday","Sunday","Monday","Tuesday","Wednesday","Thursday","Friday"};
typedef long long ll;
ll pow(ll x,ll n,ll mod)//快速幂
{
ll res=1;
while(n>0)
{
if(n%2==1)
{
res=res*x;
res=res%mod;
}
x=x*x;
x=x%mod;
n>>=1;
}
return res;
}
int main(){
int m;
while(1){
scanf("%d", &m);
int ans=0;
for(int i=1;i<=500;i++){
printf("%d ", ans);
ans=(ans+pow(i,i,7))%7;
if(i%m==0) cout<<endl;
}
}
return 0;
}
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
int mp[500]={0,1,5,4,1,4,5,5,6,0,4,6,0,6,6,0,2,0,1,6,0,0,1,5,6,3,0,6,6,0,1,4,6,5,6,6,0,2,4,5,
0,6,6,0,4,3,0,3,4,4,5,6,3,5,6,5,5,6,1,6,0,5,6,6,0,4,5,2,6,5,5,6,0,3,5,4,5,5,6,1,
3,4,6,5,5,6,3,2,6,2,3,3,4,5,2,4,5,4,4,5,0,5,6,4,5,5,6,3,4,1,5,4,4,5,6,2,4,3,4,4,
5,0,2,3,5,4,4,5,2,1,5,1,2,2,3,4,1,3,4,3,3,4,6,4,5,3,4,4,5,2,3,0,4,3,3,4,5,1,3,2,
3,3,4,6,1,2,4,3,3,4,1,0,4,0,1,1,2,3,0,2,3,2,2,3,5,3,4,2,3,3,4,1,2,6,3,2,2,3,4,0,
2,1,2,2,3,5,0,1,3,2,2,3,0,6,3,6,0,0,1,2,6,1,2,1,1,2,4,2,3,1,2,2,3,0,1,5,2,1,1,2,
3,6,1,0,1,1,2,4,6,0,2,1,1,2,6,5,2,5,6,6,0,1,5,0,1,0,0,1,3,1,2,0,1,1,2,6,0,4,1,0,
0,1,2,5,0,6,0,0,1,3,5,6,1,0
};
char c[8][10]={"Saturday","Sunday","Monday","Tuesday","Wednesday","Thursday","Friday"};
typedef long long ll;
ll pow(ll x,ll n,ll mod)//快速幂
{
ll res=1;
while(n>0)
{
if(n%2==1)
{
res=res*x;
res=res%mod;
}
x=x*x;
x=x%mod;
n>>=1;
}
return res;
}
int main(){
int t,n;
scanf("%d", &t);
mp[1]=1;
while(t--){
scanf("%d", &n);
printf("%s\n", c[mp[n%294]]);
}
return 0;
}