有两个题队友补的,先安利一波
2019hdu暑假多校第五场1004 equation HDU - 6627
2019hdu暑假多校第五场1007 permutation 2 HDU - 6630
1005 permutation 1 HDU 6628
题意:给你一个n和k,求n的全排列中,相邻两数的差值的数组字典序第k小的排列
思路:其实就是两个字,暴力.......
字典序第k小,k的范围是n!跟10000取min,8!=40320,是第一个大于10000的数,所以当n小于等于8时,使用next_permutation函数暴力找到,再按照差值排个序就好了
对于n大于8的情况因为只需要10000位,所以只需要全排列8个位子的数字就好了,由于差值字典序最小,那么我们把n放第一位,剩下的从1到n-9这些数字在n后边依次放好即可,最后把n-8到n-1这个8个数全排列一下找到第k个即可
T组询问,担心超时可以先预处理把他们都存起来,最后直接查询就ok了
#include<bits/stdc++.h>
using namespace std;
#define ll long long
struct node
{
int a[50005][15];
struct Node{
int z[15],pos;
bool operator < (const Node &x)const{
for(int i=1;i<=7;i++){
if(z[i]!=x.z[i]) return z[i]<x.z[i];
}
}
}b[50005];
}ans[25];
int main()
{
freopen("1.in","r",stdin);
int t;scanf("%d",&t);
for(int i=2;i<=20;i++){
int tmp[15];
//if(i==9) continue;
if(i<9){
int cnt = 0;
for(int j=1;j<=i;j++) tmp[j]=j;//cout<<i<<endl;
do{
cnt++;
for(int j=1;j<=i;j++){
ans[i].a[cnt][j]=tmp[j];
if(j!=1) ans[i].b[cnt].z[j-1]=tmp[j]-tmp[j-1];
}
ans[i].b[cnt].pos=cnt;
}while(next_permutation(tmp+1,tmp+1+i));
sort(ans[i].b+1,ans[i].b+cnt+1);
}
else{//cout<<1<<endl;
int cnt = 1;
for(int j=1;j<=8;j++) tmp[j]=i-9+j;
do{
for(int j=1;j<=8;j++){
ans[i].a[cnt][j]=tmp[j];
}
cnt++;
}while(next_permutation(tmp+1,tmp+9));
}
}
while(t--){
int n,k;
scanf("%d%d",&n,&k);
//if(n==9) printf("9 "),n--;
if(n<9){
for(int i=1;i<=n;i++){
int pos =
printf("%d",ans[n].a[ans[n].b[k].pos][i]);
if(i==n) puts("");
else printf(" ");
}
}
else {
printf("%d",n);
for(int i=1;i<=n-9;i++) printf(" %d",i);
for(int i=1;i<=8;i++) printf(" %d",ans[n].a[k][i]);
puts("");
}
}
return 0;
}
1006 string matching HDU 6629
题意:给你一个字符串,问从第1个字符(下标从0开始)到第n-1个字符开始求与原字符串求最长前缀时需要比较的次数
思路:这是一个exkmp模板题,exkmp可以求出一个字符串的每一个字符开始与另一个字符串的最长公共前缀长度,那么我们可以将他本身跟自己做exkmp算法,求出最长前缀长度,去掉第一位的前缀,就接近答案了,接近......那么还差哪些呢,我们求得是比较次数,相同的比较,ans++,那么不相等的也要比较,ans++,(那不是每个前缀长度+1就好了???当然不是)如果我的字符串都比到最后一位了,还相等,那这种情况跳出,就不需要去多判一次了,所以我们再累加的时候只需要判断前缀长度+当前位置-1是不是==字符串长度即可
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
#define ll long long
char sa[1100000],sb[1100000];
int lena,lenb;
int p[1100000],ex[1100000];
//p数组是用来让B串自己匹配自己的
void exkmp()
{
p[1]=lenb;
int x=1;
while(sb[x]==sb[x+1]&&x+1<=lenb) x++;//因为我们p[1]是具有一定性,所以我们不能直接用,所以要先暴力求出p[2]
p[2]=x-1;
int k=2;
for(int i=3;i<=lenb;i++)
{
int pp=k+p[k]-1,L=p[i-k+1];//pp实际上是p
if(i+L<pp+1) p[i]=L;//i-k+L<pp-k+1化简后i+L<pp
else
{
int j=pp-i+1;
if(j<0) j=0;
while(sb[j+1]==sb[i+j]&&i+j<=lenb) j++;
p[i]=j;
k=i;
}
}
x=1;
while(sa[x]==sb[x]&&x<=lenb) x++;//ex[1]并不具有一定性,所以我们暴力求出ex[1]
ex[1]=x-1;
k=1;
for(int i=2;i<=lena;i++)
{
int pp=k+ex[k]-1,L=p[i-k+1];
if(i+L<pp+1) ex[i]=L;
else
{
int j=pp-i+1;
if(j<0) j=0;
while(sb[j+1]==sa[i+j]&&i+j<=lena&&j<=lenb) j++;
ex[i]=j;
k=i;
}
}
}
int main()
{
int t;scanf("%d",&t);
while(t--){
memset(p,0,sizeof p);
memset(ex,0,sizeof ex);
scanf("%s",sa+1);
strcpy(sb+1,sa+1);
lena=strlen(sa+1);lenb=strlen(sb+1);
ll ans = 0;
exkmp();
for(int i=2;i<=lena;i++) {
if(lena-i+1==ex[i]) ans+=1l*ex[i];
else ans+=1l*(ex[i]+1);
}
printf("%lld\n",ans);
}
return 0;
}