2019 Multi-University Training Contest 5

本篇博客主要用于自己学习,没有过多的讲解,请见谅。

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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值