SUST 20/3/27 题解

题目链接:
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) ap11(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 NNN=7K1+m1K100m1<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 m17m16%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 NNN=6K2+m2K200m2<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种情况会循环出现 0m1<7,0m2<676=42

但 每 42 个 数 后 他 们 得 起 始 数 字 会 发 生 改 变 , 所 以 总 循 环 数 为 7 ∗ 42 = 294 但每42个数后他们得起始数字会发生改变,所以总循环数为7*42=294 42742=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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值