本篇博客主要用于自己学习,没有过多的讲解,请见谅。
HDU 6229 string matching
题意:题目先给你一段代码,然后问你这个代码会比较多少次。实际上就是求字符串的所有后缀和这个字符串的公共前缀加1(如果公共前缀等于这个后缀本身就不用加1了,否则要加1),求和输出就行了。
签到题,实际上这是个扩展KMP模板题,不过由于我们队不知道扩展KMP这个东西,所以很晚才过这个题。
#include<bits/stdc++.h>
#define mem(a,b) memset((a),b,sizeof(a))
#define de cout<<endl<<endl<<endl
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=100010;
using namespace std;
//extend[i]表示T与S[i,n-1]的最长公共前缀,要求出所有extend[i](0<=i<n)。
const int maxn=1000010; //字符串长度最大值
int Next[maxn],ex[maxn]; //ex数组即为extend数组
//预处理计算Next数组
void GetNext(char *str)
{
int i=0,j,po,len=strlen(str);
Next[0]=len;//初始化Next[0]
while(str[i]==str[i+1]&&i+1<len)//计算Next[1]
i++;
Next[1]=i;
po=1;//初始化po的位置
for(i=2;i<len;i++)
{
if(Next[i-po]+i<Next[po]+po)//第一种情况,可以直接得到Next[i]的值
Next[i]=Next[i-po];
else//第二种情况,要继续匹配才能得到Next[i]的值
{
j=Next[po]+po-i;
if(j<0)j=0;//如果i>po+Next[po],则要从头开始匹配
while(i+j<len&&str[j]==str[j+i])//计算Next[i]
j++;
Next[i]=j;
po=i;//更新po的位置
}
}
}
//计算extend数组
void ExKMP(char *S,char *T)//S1 S s2 T
{
int i=0,j,po,lens=strlen(S),lent=strlen(T);
GetNext(T);//计算子串的Next数组
while(S[i]==T[i]&&i<lent&&i<lens)//计算ex[0]
i++;
ex[0]=i;
po=0;//初始化po的位置
for(i=1;i<lens;i++)
{
if(Next[i-po]+i<ex[po]+po)//第一种情况,直接可以得到ex[i]的值
ex[i]=Next[i-po];
else//第二种情况,要继续匹配才能得到ex[i]的值
{
j=ex[po]+po-i;
if(j<0)j=0;//如果i>ex[po]+po则要从头开始匹配
while(i+j<lens&&j<lent&&S[j+i]==T[j])//计算ex[i]
j++;
ex[i]=j;
po=i;//更新po的位置
}
}
}
char a[1000010],b[1000010];
int main()
{
int T;scanf("%d",&T);
getchar();
while(T--)
{
scanf("%s",a);
int n=strlen(a);
for(int i=0;i<n;i++)
b[i]=a[i];
GetNext(a);
ExKMP(a,b);
ll ans=0;
for(int i=1;i<=n-1;i++)
{
if(ex[i]<n-i)
ans+=(ex[i]+1);
else
ans+=ex[i];
}
printf("%lld\n",ans);
}
return 0;
}
//https://blog.csdn.net/dyx404514/article/details/41831947
HDU 6628 permutation 1
题意:给你两个数n,k,让你求出 n 的所有全排列中第 k 小的排列,这里的第k小不是字典序第k小,而是题目给你定义了小于运算符,由给定序列生成一个序列,然后按照生成的序列的字典序排列,生成序列的方式:原序列 p1,p2,…,pn ,则生成序列为:p2−p1,p3−p2,…,pn−pn−1。(由n项变成了n-1项)。
实际上当n等20时,前12位已经确定,因为8!=40320,而k不超过10000,所以,后面暴力枚举就行了,40320*40=1612800,1s也不会超时。当n小于等于8时,直接暴力枚举,因为8!=40320,40320*40=1612800,1s绝对不超时。当n等于9的时候,特判一下。
这个题,比赛时候代码写的特别特别乱,比赛完也没有整理......不过别人好像都是dfs过的,我是分情况讨论,暴力模拟过的。看到杭电给的题解好像就是dfs,抽时间得看看咋写,好像还说字典序这种东西dfs写好像比较好。
还有,这个题T组输入,第T组输出后面还得加一个空行,我以为那个不能加,结果PE了2次......
#include<bits/stdc++.h>
#define mem(a,b) memset((a),b,sizeof(a))
#define de cout<<endl<<endl<<endl
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=100010;
using namespace std;
struct node{
int b[20];
int c[20];
}a[410010];
int n,nn,nnn,k,p;
bool cmp1(node a1,node a2)
{
for(int i=1;i<=n;i++)
{
if(a1.c[i]<a2.c[i])
return true;
if(a1.c[i]>a2.c[i])
return false;
}
}
bool cmp2(node a1,node a2)
{
for(int i=2;i<=n-2;i++)
{
if(a1.b[i]<a2.b[i])
return true;
if(a1.b[i]>a2.b[i])
return false;
}
}
bool cmp3(node a1,node a2)
{
for(int i=1;i<=n-3;i++)
{
if(a1.b[i]<a2.b[i])
return true;
if(a1.b[i]>a2.b[i])
return false;
}
}
bool cmp4(node a1,node a2)
{
n=nnn;
//cout<<"## "<<n<<" "<<p<<endl;//exit(0);
for(int i=1;i<=n-p-1;i++)
{
if(a1.b[i]<a2.b[i])
return true;
if(a1.b[i]>a2.b[i])
return false;
}
}
int main()
{
int T1;
scanf("%d",&T1);
int T=T1;
while(T1--)
{
T--;
if(T<0)
break;
//cout<<T<<endl;
scanf("%d%d",&n,&k);
int d[20];
for(int i=1;i<=n;i++)
d[i]=i;
int cnt=0;
if(n<=8)
{
cnt=0;
do
{
cnt++;
for(int i=1;i<=n;i++)
a[cnt].b[i]=d[i];
}while(next_permutation(d+1,d+n+1));
for(int i=1;i<=cnt;i++)
for(int j=2;j<=n;j++)
a[i].c[j-1]=a[i].b[j]-a[i].b[j-1];
sort(a+1,a+cnt+1,cmp1);
printf("%d",a[k].b[1]);
for(int i=2;i<=n;i++)
printf(" %d",a[k].b[i]);
//if(T!=0)
printf("\n");
continue;
}
if(n==9)
{
if(k<=5040)
{
printf("%d 1",n);
cnt=0;
do
{
cnt++;
for(int i=2;i<=n-1;i++)
a[cnt].b[i]=d[i];
}while(next_permutation(d+2,d+n));
for(int i=1;i<=cnt;i++)
for(int j=3;j<=n-1;j++)
a[i].c[j-1]=a[i].b[j]-a[i].b[j-1];
sort(a+1,a+cnt+1,cmp2);
for(int i=2;i<=n-1;i++)
printf(" %d",a[k].b[i]);
//if(T!=0)
printf("\n");
continue;
}
else
{
k-=5040;
printf("%d 2",n);
cnt=0;
d[1]=1;
for(int i=3;i<=n-1;i++)
d[i-1]=i;
do
{
cnt++;
for(int i=1;i<=n-2;i++)
a[cnt].b[i]=d[i];
}while(next_permutation(d+1,d+n-1));
for(int i=1;i<=cnt;i++)
for(int j=2;j<=n-2;j++)
a[i].c[j-1]=a[i].b[j]-a[i].b[j-1];
sort(a+1,a+cnt+1,cmp3);
for(int i=1;i<=n-2;i++)
printf(" %d",a[k].b[i]);
//if(T!=0)
printf("\n");
continue;
}
}
if(k<=5040)
{
printf("%d 1",n);
p=n-8;
p--;
p++;
for(int i=2;i<=p;i++)
printf(" %d",i);
for(int i=p+1;i<=n-1;i++)
d[i-p]=i;
int pp=p,nn=n;
cnt=0;
do
{
cnt++;
for(int i=1;i<=n-p-1;i++)
a[cnt].b[i]=d[i];
}while(next_permutation(d+1,d+n-p));
p=pp;
n=nn;
for(int i=1;i<=cnt;i++)
for(int j=2;j<=n-p-1;j++)
a[i].c[j-1]=a[i].b[j]-a[i].b[j-1];
nn=n;
nnn=n;
sort(a+1,a+cnt+1,cmp4);
for(int i=1;i<=n-p-1;i++)
printf(" %d",a[k].b[i]);
//if(T!=0)
printf("\n");
continue;
}
else
{
printf("%d 1",n);
p=n-8;
p--;
for(int i=2;i<=p;i++)
printf(" %d",i);
d[p+1]=p+2;
printf(" %d",d[p+1]);
p++;
int cntt=p;
int p1=cntt+1;
for(int i=p;i<=n-1;i++)
{
if(i!=p+1)
{d[++cntt]=i;}
}
int p2=cntt;
int pp=p,nn=n;
cnt=0;
do
{
cnt++;
for(int i=p1;i<=p2;i++)
a[cnt].b[i-p1+1]=d[i];
}while(next_permutation(d+p1,d+p2+1));
p=pp;
n=nn;
for(int i=1;i<=cnt;i++)
for(int j=2;j<=n-p-1;j++)
a[i].c[j-1]=a[i].b[j]-a[i].b[j-1];
nn=n;
nnn=n;
sort(a+1,a+cnt+1,cmp4);
k-=5040;
for(int i=1;i<=n-p-1;i++)
printf(" %d",a[k].b[i]);
//if(T!=0) //不要加这行,否则会PE
printf("\n");
continue;
}
}
return 0;
}
HDU 6630 permutation 2
题意:给你 n , x , y,让你求n的全排列中有多少种满足要求的情况。需要满足3个要求:1、第一个数是x;2、第二个数是y;3、任意两个相邻的差的绝对值不能超过2。这个题可以打表找规律推公式。a[n]=a[n-1]+a[n-3];然后分4种情况讨论就行了,详见代码。
#include<bits/stdc++.h>
#define mem(a,b) memset((a),b,sizeof(a))
#define de cout<<endl<<endl<<endl
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int N=100010;
const int mod=998244353;
using namespace std;
ll a[100010];
int main()
{
a[0]=1;
a[1]=1;
a[2]=1;
a[3]=2;
for(int i=4;i<100010;i++)
a[i]=(a[i-1]+a[i-3])%mod;
int n,x,y;
ll ans;
int T;scanf("%d",&T);
while(T--)
{
ans=0;
scanf("%d%d%d",&n,&x,&y);
if(x==1&&y==n)
{printf("%lld\n",a[y-x]);continue;}
if(x!=1&&y==n)
{printf("%lld\n",a[y-(x+1)]);continue;}
if(x==1&&y!=n)
{printf("%lld\n",a[y-x-1]);continue;}
if(x!=1&&y!=n)
{
if(y==x+1)
{
printf("0\n");
continue;
}
printf("%lld\n",a[y-1-(x+1)]);
continue;
}
}
return 0;
}
HDU 6627 equation
题意:题意:给你一个一个式子sigma( abs(ai*x+bi) ) = C (i从1到n),求满足式子的 x 的解有多少个,并输出它们。
这题搞明白了,实际上就是一个模拟题,注意一下细节就行了。代码看着还是有点乱......
#include<bits/stdc++.h>
#define mem(a,b) memset((a),b,sizeof(a))
#define de cout<<endl<<endl<<endl
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=100010;
using namespace std;
int n,c,cnt;
struct node{
int a,b;int f;
double ling;
}no[100010],ans[100010],ansp[100010];
bool cmp(node a1,node a2)
{
return a1.b*(-1.0)/a1.a>a2.b*(-1.0)/a2.a;
}
bool cmpp(node ans1,node ans2)
{
if(ans1.f==1&&ans2.f==0)
return true;
if(ans1.f==0&&ans2.f==1)
return false;
if(ans1.f==0&&ans2.f==0)
return ans1.a*1.0/ans1.b<ans2.a*1.0/ans2.b;
if(ans1.f==1&&ans2.f==1)
return ans1.a*1.0/ans1.b>ans2.a*1.0/ans2.b;
}
int apre[100010],aaft[100010],bpre[100010],baft[100010];
int main()
{
int T;scanf("%d",&T);
while(T--)
{
mem(apre,0);mem(aaft,0);mem(bpre,0);mem(baft,0);
cnt=0;
scanf("%d%d",&n,&c);
for(int i=1;i<=n;i++)
scanf("%d%d",&no[i].a,&no[i].b),no[i].ling=no[i].b*(-1.0)/no[i].a;
sort(no+1,no+n+1,cmp);
no[n+1].ling=1e9;
for(int i=1;i<=n;i++)
apre[i]=apre[i-1]+no[i].a,bpre[i]=bpre[i-1]+no[i].b;
for(int i=n;i>=1;i--)
aaft[i]=aaft[i+1]+no[i].a,baft[i]=baft[i+1]+no[i].b;
int flag=0;
double anss;
for(int i=1;i<=n;i++)//0 i-1 fu i n zheng
{
if(i==1)
{
if(aaft[1]==0&&(baft[1]==c||baft[1]==-c))
{flag++;break;}
if(aaft[1]==0)
continue;
anss=(c-baft[1])*1.0/aaft[1];
if(anss>=no[i].ling)
{
cnt++;
if((c-baft[1]<0&&aaft[1]>0)||(c-baft[1]>0&&aaft[1]<0))
ans[cnt].f=1,ans[cnt].a=baft[1]-c,ans[cnt].b=aaft[1];
else
ans[cnt].f=0;ans[cnt].a=c-baft[1];ans[cnt].b=aaft[1];
}
continue;
}
int aa=aaft[i]-apre[i-1];
int bb=baft[i]-bpre[i-1];
if(aa==0&&bb==c)
{flag++;break;}
if(aa==0)
continue;
anss=(c-bb)*1.0/aa;
if(anss<=no[i-1].ling&&anss>=no[i].ling)
{
cnt++;
if((c-bb<0&&aa>0)||(c-bb>0&&aa<0))
ans[cnt].f=1,ans[cnt].a=c-bb,ans[cnt].b=aa;
else
ans[cnt].f=0,ans[cnt].a=c-bb,ans[cnt].b=aa;
}
}
anss=-1.0*(c+baft[1])/aaft[1];
if(anss<=no[n].ling) //quan fu
{
cnt++;
if((c+baft[1]>0&&aaft[1]>0)||(c+baft[1]<0&&aaft[1]<0))
ans[cnt].f=1,ans[cnt].a=c+baft[1],ans[cnt].b=aaft[1];
else
ans[cnt].f=0,ans[cnt].a=c+baft[1],ans[cnt].b=aaft[1];
}
if(flag>0)
{printf("-1\n");continue;}
for(int i=1;i<=cnt;i++)
{
if(ans[i].a<0) ans[i].a=-1*ans[i].a;
if(ans[i].b<0) ans[i].b=-1*ans[i].b;
}
sort(ans+1,ans+cnt+1,cmpp);
int cntt=0;
for(int i=1;i<=cnt;i++)
{
if(ans[i].a==0)
ans[i].b=1;
else
{
int k=__gcd(ans[i].a,ans[i].b);
ans[i].a/=k;ans[i].b/=k;
}
if(ans[i].f==ans[i-1].f&&ans[i].a==ans[i-1].a&&ans[i].b==ans[i-1].b)
continue;
ansp[++cntt].f=ans[i].f;ansp[cntt].a=ans[i].a;ansp[cntt].b=ans[i].b;
}
printf("%d",cntt);
for(int i=1;i<=cntt;i++)
{
if(ansp[i].f==0)
printf(" %d/%d",ansp[i].a,ansp[i].b);
else
printf(" -%d/%d",ansp[i].a,ansp[i].b);
}
printf("\n");
}
return 0;
}