BestCoder Round #78

来源:互联网 发布:ubuntu社区中文版 编辑:程序博客网 时间:2024/06/07 22:40

A题 链接:http://acm.hdu.edu.cn/showproblem.php?pid=5655

官方题解:

By NanoApe 构成四边形的条件:最长边小于其余三条边的和

坑点1:假如有条长度为0的边的话,哪里来的四条边呢?

坑点2:其余三条边的和会爆longlong,我们可以将a+b+c>d换成a>d-b-c来求解

我的理解:

没想到a+b+c>d转化成a>d-b-c,想到经常自己写程序相加爆longlong的话会变成负的,那肯定是大于第四条边了,利用了下这个条件,过了

#include<cstdio>#include<algorithm>#include<cstring>using namespace std;#define LL __int64int main(){    int T;    LL a,b,c,d,maxn,sum,sum1;    scanf("%d",&T);    while(T--)    {        scanf("%I64d%I64d%I64d%I64d",&a,&b,&c,&d);        if(a==0||b==0||c==0||d==0)        {            printf("No\n");            continue;        }        maxn=max(max(a,b),max(c,d));        sum=-maxn;        sum+=a;        sum1=sum;        sum+=b;        if(sum<sum1){printf("Yes\n");continue;}        sum1=sum;        sum+=c;        if(sum<sum1){printf("Yes\n");continue;}        sum1=sum;        sum+=d;        if(sum<sum1){printf("Yes\n");continue;}        sum1=sum;        if(sum>maxn)            printf("Yes\n");        else            printf("No\n");    }}

B题 链接:http://acm.hdu.edu.cn/showproblem.php?pid=5656

官方题解:

By YJQ 我们令dp[i][j]表示在前i个数中,选出若干个数使得它们的gcd为j的方案数,于是只需要枚举第i+1个数是否被选中来转移就可以了

令第i+1个数为v,当考虑dp[i][j]的时候,我们令dp[i+1][j] += dp[i][j]dp[i+1][j]+=dp[i][j](v 不选),dp[i+1][gcd(j,v)] += dp[i][j]dp[i+1][gcd(j,v)]+=dp[i][j](v 选)

复杂度O(N*MaxV) MaxV 为出现过的数的最大值

其实有O(MaxV *log(MaxV))的做法,我们考虑记f[i]表示从这些数中选择若干个数,使得他们的gcd是i的倍数的方案数。假如有K个数是i的倍数,则f[i]=2^K-1,再用g[i]表示从这些数中选择若干个数,使得他们的gcd是i的方案数,则g[i]=f[i] - g[j] (对于所有j是i的倍数)。

由调和级数可以得到复杂度为O(MaxV *log(MaxV))

我的理解:

当时做的时候,就钻进爆搜的眼里面去了,一直在想怎么预处理加快速度,就跟掉钱眼了一样,拔不出来,o(╯□╰)o,比赛的时候也一样,希望下次不要死钻一个方向,多方向解题。

dp[i]记录gcd为i的方案数

#include<cstdio>#include<cstring>using namespace std;const int N=1005;const int mod=1e8+7;#define ll __int64int a[N],g[N][N];ll dp[N];int gcd(int a,int b){    return b==0?a:gcd(b,a%b);}int main(){    int i,j,T,n;    for(i=1;i<=1000;i++)    {        for(j=1;j<=1000;j++)            g[i][j]=g[j][i]=gcd(i,j);    }    scanf("%d",&T);    while(T--)    {        scanf("%d",&n);        for(i=0;i<n;i++)            scanf("%d",&a[i]);        memset(dp,0,sizeof(dp));        for(i=0;i<n;i++)        {            for(j=1;j<=1000;j++)            {                if(!dp[j])continue;                int t=g[a[i]][j];                dp[t]=dp[t]+dp[j];                if(dp[t]>mod) dp[t]%=mod;            }            dp[a[i]]++;        }        ll ans=0;        for(i=1;i<=1000;i++)        {            if(!dp[i])continue;            (ans+=(i*dp[i]%mod))%=mod;        }        printf("%I64d\n",ans);    }    return 0;}

D题 链接:http://acm.hdu.edu.cn/showproblem.php?pid=5658

官方题解:

By NanoApe 由于字符串长度最多为1000,不同的询问最多也只有500500种,那么我们先把所有询问的答案预处理出来即可。

从小到大枚举左端点,再从小到大移动右端点,用回文树维护本质不同的回文子串。

设我们现在枚举的区间是[l,r],下一步是[l,r+1],那么就相当于在回文树所维护的字符串的后面添加一个字符。当左端点改变时,重建回文树。

复杂度O(n^2)

其实还可以用manacher,在扩展的时候用Hash去重,复杂度O(n^2)


我的题解:

回文树= = 以后再看吧

#include<cstdio>#include<cstring>using namespace std;typedef long long ll;const int maxn=1100;int n,q;char s[maxn];int l,r;ll ans[maxn][maxn];struct PalinTree{    int ch[maxn][26],f[maxn];    int n,tot,last;    int len[maxn],cnt[maxn];    int s[maxn];    int newnode(int l)    {        memset(ch[tot],0,sizeof(ch[tot]));        cnt[tot]=0;        len[tot]=l;        return tot++;    }    void init()    {        tot=0;        newnode(0);        newnode(-1);        last=0;n=0;        s[n]=-1;f[0]=1;    }    int get_fail(int x)    {        while(s[n-len[x]-1]!=s[n])            x=f[x];        return x;    }    void add(int c)    {        c-='a';        s[++n]=c;        last=get_fail(last);        if(!ch[last][c])        {            int cur=newnode(len[last]+2);            f[cur]=ch[get_fail(f[last])][c];            ch[last][c]=cur;        }        last=ch[last][c];        cnt[last]++;    }}pt;void init(){    int len=strlen(s+1);    for(int l=1;l<=len;l++)    {        pt.init();        for(int r=l;r<=len;r++)        {            pt.add(s[r]);            ans[l][r]=pt.tot-2;        }    }}int main(){    while(~scanf("%d",&n))    {        scanf("%s",s+1);        init();        scanf("%d",&q);        while(q--)        {            scanf("%d%d",&l,&r);            printf("%I64d\n",ans[l][r]);        }    }    return 0;}



0 0
原创粉丝点击