Bestcoder round#32 解题报告

1001

按照题目要求写出cmp函数,sort一下就行了。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>

using namespace std;
struct node
{
    int d,y,id;
}a[1100000];
int n;
int cmp(node a,node b)
{
    if (a.d!=b.d) return a.d>b.d;
    if (a.y!=b.y) return a.y<b.y;
    return a.id<b.id;
}
int main()
{
    while (scanf("%d",&n)==1)
    {
        for (int i=0;i<n;i++)
        {
            int x,y;
            scanf("%d %d",&x,&y);
            a[i].d=x-y,a[i].y=y,a[i].id=i;
        }
        sort(a,a+n,cmp);
        for (int i=0;i<n;i++)
        {
            if (i!=0) printf(" ");
            printf("%d",a[i].id);
        }
        printf("\n");
    }
    return 0;
}

1002

我们把前缀和 s[i] ,从后往前依次插入到set里,如果当前下标为奇数,我们需要找set中是否存在一个数 x ,使得xs[i]=k,即 x=k+s[i] ;如果当前下标为偶数,我们需要找set中是否存在一个数 x ,使得xs[i]=k,即 x=k+s[i] 。卡着内存过的。。。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
using namespace std;
typedef long long LL;
int T;
LL a[1100000],s[1100000];
int n,cas;
LL k;
set<LL> S;
int main()
{
    scanf("%d",&T);
    while (T--)
    {
        S.clear();
        int flag=0;
        scanf("%d %I64d",&n,&k);
        for(int i=1;i<=n;i++)
            scanf("%I64d",&a[i]);
        for (int i=1;i<=n;i++)
        {
            if (i&1) s[i]=s[i-1]+a[i];
            else s[i]=s[i-1]-a[i];
        }
        for (int i=n;i>=0;i--)
        {
            S.insert(s[i]);
            if (i&1)
            {
                if (S.count(-k+s[i])==1)
                {
                    flag=1;
                    break;
                }
            }
            else
            {
                if (S.count(k+s[i])==1)
                {
                    flag=1;
                    break;
                }
            }
        }
        if(flag) printf("Case #%d: Yes.\n",++cas);
        else printf("Case #%d: No.\n",++cas);
    }
    return 0;
}

1003

首先判断已有的括号序列是否合法,以及n是否为奇数。我们设已有的括号序列中有a个左括号,b个右括号。因为总序列长度为n,我们设m=n/2,那么最终的括号序列有m个左括号和m个右括号。题目的答案相当于从(a,b)到(m,m)且不超过y=x这条线的方案数。很容易发现,这个答案相当于找从(0,0)到(p,q)且不超过y=x这条线的方案数,p=m-a,q=m-b。这个答案就相当于(0,-1)到(p,q-1)切与y=x这条线没有交点的方案数。因为从(0,-1)到(d,d)的方案数相当于从(-1,0)到(d,d)的方案数,则不合法的答案数相当于从(-1,0)到(p,q-1)且与y=x有至少一个交点的答案数,很容易发现,从(-1,0)到(p,q-1)的路线必与(p,q-1)有交点,所以不合法的答案数即为从(-1,0)到(p,q-1)的路线数。则原答案为

Cpp+qCq1p+q=(pq+1)Cqp+qp+1
。组合数的值可以利用预处理得到。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>

using namespace std;
typedef long long LL;
const LL mod=1e9+7;

int l,n;
char s[1100000];
LL inv[1100000],ff[1100000],f[1100000];
int flag,tail;
LL a,b;
LL C(int n,int m)
{
    LL res=(f[n]*inv[m])%mod;
    res=(res*inv[n-m])%mod;
    return res;
}
int main()
{
    f[0]=1;
    for (int i=1;i<=1000010;i++)
        f[i]=(f[i-1]*i)%mod;
    ff[1]=ff[0]=inv[1]=inv[0]=1;  
    for (int i=2;i<=1000010;i++)
    {
        inv[i]=(LL)(mod-mod/i)*inv[mod%i]%mod;
        ff[i]=inv[i];
    }
    for (int i=2;i<=1000010;i++)
        inv[i]=(inv[i-1]*inv[i])%mod;
    while (scanf("%d",&n)==1)
    {
        scanf("%s",s);
        l=strlen(s);
        flag=0;
        a=b=0;
        if (n&1)
        {
            printf("0\n");
            continue;
        }
        tail=0;
        for (int i=0;i<l;i++)
            if (s[i]=='(') tail++,a++;
            else 
            {
                b++;
                if (tail==0)
                {
                    flag=1;
                    break;
                }
                tail--;
            }
        if (flag)
        {
            printf("0\n");
            continue;
        }
        LL m=n/2;
        LL p=m-a,q=m-b;
        LL ans=C(a+b,a);
        ans=(ans*(p-q+1))%mod;
        ans=(ans*ff[p+1])%mod;
        cout<<ans<<endl;
    }
    return 0;
}

1004

很容易发现, x1 xn 中最多只有1~ n 这些数。我们设dp[i][j]表示利用前i种数字到达和j的方案数。那么dp[i][j]=dp[i][j-i]+dp[i-1][j-i]。表示前一个数是i或者i-1。O(n* n )的时间内可以得到答案。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>

using namespace std;

int T,cas;
int n,m;
int dp[400][51000];
int ans;
int main()
{
    cin>>T;
    while (T--)
    {
        cin>>n>>m;
        dp[0][0]=1;
        ans=0;
        for (int i=1;i*i<=2*n;i++)
        {
            for (int j=i;j<=n;j++)
                dp[i][j]=(dp[i-1][j-i]+dp[i][j-i])%m;
            ans=(ans+dp[i][n])%m;
        }
        printf("Case #%d: %d\n",++cas,ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值