哈希+组合数学+思维
Posted 钟钟终
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了哈希+组合数学+思维相关的知识,希望对你有一定的参考价值。
B. Password
做法有很多,kmp、哈希都可以。wa麻了,调了2个小时才接受自己的做法有问题,固执。
思路:
1.可用哈希手法O(1)判断一个字符串的两端子串是否相同。
2.对字符串的长度进行二分,若这一段(从第二个字符~第n-1的字符)的哈希值等于首部、尾部字符串,则成立。
代码:
#include <bits/stdc++.h>
#define int long long
#define ios cin.tie(0),cout.tie(0),ios::sync_with_stdio(0);
#define endl '\\n'
#define ULL unsigned long long
using namespace std;
const double eps=1e-8;
const int mod=998244353;
const int N=1e6+5;
const int P=131;
ULL p[N],h[N];
char s[N];
int a[N],n,cnt;
int init(char s[])
p[0]=1,h[0]=0;
int len=strlen(s+1);
for(int i=1;i<=len;i++)
p[i]=p[i-1]*P;
h[i]=h[i-1]*P+s[i];
return h[len];
//计算s[l-r]之间的hash值
ULL get(int l,int r)
return h[r]-h[l-1]*p[r-l+1];
//判断两子串是否相同
bool subs(int l1,int r1,int l2,int r2)
return get(l1,r1)==get(l2,r2);
bool check(int len,int val)
for(int i=2;i+len-1<n;i++)
if(get(i,i+len-1)==val) return 1;
return 0;
void solve()
cin>>(s+1);
n=strlen(s+1);
init(s);
for(int i=1;i<n;i++)
if(subs(1,i,n-i+1,n)) a[++cnt]=i;
int l=0,r=cnt,mid=0,ans=0;
while(l<=r)
mid=(l+r)/2;
if(check(a[mid],get(1,a[mid]))) ans=mid,l=mid+1;
else r=mid-1;
if(ans==0)
cout<<"Just a legend"<<endl;
else
for(int i=1;i<=a[ans];i++) cout<<s[i];cout<<endl;
signed main()
ios;
//int T;cin>>T;
//while(T--)
solve();
return 0;
放一下自己tle的代码:
#include <bits/stdc++.h>
#define int long long
#define ios cin.tie(0),cout.tie(0),ios::sync_with_stdio(0);
#define endl '\\n'
#define ULL unsigned long long
using namespace std;
const double eps=1e-8;
const int mod=998244353;
const int N=1e6+5;
const int P=131;
ULL pl[N],h[N];
int init(char s[])
pl[0]=1,h[0]=0;
int len=strlen(s+1);
for(int i=1;i<=len;i++)
pl[i]=pl[i-1]*P;
h[i]=h[i-1]*P+s[i];
return h[len];
//计算s[l-r]之间的hash值
ULL get(int l,int r)
return h[r]-h[l-1]*pl[r-l+1];
//判断两子串是否相同
bool subs(int l1,int r1,int l2,int r2)
return get(l1,r1)==get(l2,r2);
char s[N],s1[N],s2[N],s3[N],s4[N],ans[N];
int p[N];
void pre(char s2[],int m)
p[1]=0;int j=0;
for(int i=1;i<m;i++)
while(j>0&&s2[j+1]!=s2[i+1])
j=p[j];
if(s2[j+1]==s2[i+1])
j++;
p[i+1]=j;
int kmp(char s1[],char s2[],int g)
int n=strlen(s1+1),m=strlen(s2+1);
//for(int i=1;i<=n;i++) cout<<s1[i];cout<<endl;
//for(int i=1;i<=m;i++) cout<<s2[i];cout<<endl;
pre(s2,m);
int j=0;
for(int i=0;i<n;i++)
while(j>0&&s2[j+1]!=s1[i+1])
j=p[j];
if(s2[j+1]==s1[i+1]) j++;
if(j==m)
//cout<<g<<" "<<i+2-m<<endl;
if(i+1-m!=g) return 1;
j=p[j];
return 0;
void solve()
cin>>(s+1);
int n=strlen(s+1);
int gg=1;
for(int i=2;i<=n;i++)
if(s[i]==s[i-1]) continue;
else gg=0;
if(gg&&n>2)
for(int i=1;i<=n-2;i++) cout<<s[i];cout<<endl;return;
int flag=0;
init(s);
int g=0;
for(int i=1,j=n;i<n;i++,j--)
//cout<<s1<<" "<<s2<<endl;
if(subs(1,i,j,n))
for(int j=1;j<=i;j++) s1[j]=s[j];
for(int j=1;j<=n-1;j++) s3[j]=s[j];
//s1=s.substr(1,i);
//s3=s.substr(1,n-1);
//cout<<s1<<" "<<s3<<endl;
if(kmp(s3,s1,0)==1)
//cout<<"11 "<<s3<<" "<<s1<<endl;
flag=1;
for(int j=1;j<=i;j++) ans[j]=s1[j],g=i;
for(int j=2;j<=n;j++) s4[j]=s[j];
//s4=s.substr(2,n-1);
if(kmp(s4,s1,n-i-1)==1)
//cout<<"22 "<<s4<<" "<<s1<<endl;
flag=1;for(int j=1;j<=i;j++) ans[j]=s1[j],g=i;
if(flag)
for(int i=1;i<=g;i++) cout<<ans[i];
cout<<endl;
else
cout<<"Just a legend"<<endl;
signed main()
ios;
//int T;cin>>T;
//while(T--)
solve();
return 0;
C. Card Game
这道C题比其他很多C都要难一点感觉。主要围绕最大牌进行讨论,利用组合数学算出方案数,也可用dp来写。
#include <bits/stdc++.h>
#define int long long
#define ios cin.tie(0),cout.tie(0),ios::sync_with_stdio(0);
#define endl '\\n'
using namespace std;
const double eps=1e-8;
const int mod=998244353;
const int N=1e6+5;
int n,f[66],fac[66],inv[66];
int qpow(int x,int y)
int res=1;
while(y)
if(y&1) res=res*x%mod;
x=x*x%mod;y>>=1;
return res;
int getinv(int x) return qpow(x,mod-2);
int C(int n,int m)
return fac[n]*inv[m]%mod*inv[n-m]%mod;
void solve()
cin>>n;
cout<<f[n]<<" "<<(C(n,n/2)-1-f[n]+mod)%mod<<" "<<1<<endl;
signed main()
//ios;
fac[0]=1;
for(int i=1;i<=60;i++) fac[i]=fac[i-1]*i%mod;
inv[60]=getinv(fac[60]);
for(int i=60;i>=1;i--) inv[i-1]=inv[i]*i%mod;
f[2]=1;f[4]=3;
for(int i=6;i<=60;i+=2)
//cout<<C(i,i/2)<<endl;
f[i]=((C(i-1,i/2-1)+C(i-4,i/2-1))%mod+f[i-4])%mod;
//cout<<f[i]<<endl;
int T;cin>>T;
while(T--)
solve();
return 0;
B. Playing with GCD
这个B wa了好几次,还是总结一下吧。
1.刚开使思考到的点:前一个数必须大于等于下一个数,此外取模结果要为0.没把它定义为一个构造题。
2.然后发现了一组样例:a[i]:16 5
,此刻b[i]:16 80 5
最优。发现了最小公倍数的关系,再按照题意进行构造。若发现gcd(b[i-1],b[i])!=a[i-1]
,则不成立。
#include <bits/stdc++.h>
#define int long long
#define ios cin.tie(0),cout.tie(0),ios::sync_with_stdio(0);
#define endl '\\n'
#define ULL unsigned long long
using namespace std;
const double eps=1e-8;
const int mod=998244353;
const int N=1e6+5;
const int P=131;
int n,a[N],b[N];
void solve()
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
b[1]=a[1];;
int flag=以上是关于哈希+组合数学+思维的主要内容,如果未能解决你的问题,请参考以下文章