浙江中医药大学程序设计代表队2018年训练赛三十一

A题题目链接

题意:

高精度乘法

思路:

高精度乘法

C++代码:

#include<bits/stdc++.h>
using namespace std;
 
char a[10010];
char b[10010];
int ans[20010];
 
int main()
{
    while ( scanf ( "%s %s" , a , b )==2 )
    {
        memset ( ans , 0 , sizeof(ans) );
        int lena = strlen(a);
        int lenb = strlen(b);
        for ( int i=0,j=lena-1 ; i<j ; i++,j-- )
            swap ( a[i] , a[j] );
        for ( int i=0,j=lenb-1 ; i<j ; i++,j-- )
            swap ( b[i] , b[j] );
        for ( int i=0 ; i<lena ; i++ )
            for ( int j=0 ; j<lenb ; j++ )
                ans[i+j] += (a[i]-'0')*(b[j]-'0');
        int c = 0,f = 0;
        for ( int i=0 ; i<lena+lenb-1 ; i++ )
        {
            ans[i] = ans[i]+c;
            c = ans[i]/10;
            ans[i] %=  10;
        }
        if ( c>0 )
            printf ( "%d" , c ),f=1;
        for ( int i=lena+lenb-2 ; i>=0 ; i-- )
            if ( ans[i]>0||f==1 ) printf ( "%d" , ans[i] ),f=1;
        if ( f==0 )
            printf ( "0" );
        printf ( "\n" );
    }
    return 0;
}

B题题目链接

题意:

有n个小团体,a[i]表示小团体人数b[i]表示小团体所在位置,要求所有人分散开来(即没有两个人在同一位置),求走动距离最远的人走动的最小距离。

思路:

二分+贪心。明显可以看出此题的答案具有单调性(单调性解释:比如说如果题目的答案为3,那么4也符合题目要求只不过不是最优解罢了)因为答案具有单调性,于是可以采用二分的方式求解答案。

答案检验。比如说如果当前检验答案为mid,那么对于第i个团体可以分散的范围为[b[i]-mid,b[i]+mid],只要当前范围剩余空位小于a[i]则表示当前答案一定是不可行解。那如何分散人呢?尽量将人分散到可行区间的左边!

C++代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1010;
 
int n,a[maxn],b[maxn];
 
bool ok( int mid )
{
    int now = b[1]-mid;
    for ( int i=1 ; i<=n ; i++ )
    {
        now = max( now , b[i]-mid );
        if ( b[i]+mid-now+1<a[i] )
            return false;
        now = now+a[i];
    }
    return true;
}
 
int main()
{
    while ( scanf ( "%d" , &n )==1 )
    {
        for ( int i=1 ; i<=n ; i++ )
            scanf ( "%d" , &a[i] );
        for ( int i=1 ; i<=n ; i++ )
            scanf ( "%d" , &b[i] );
        int l=0,r=100000000,mid;
        while( l<=r )
        {
            mid = (l+r)>>1;
            if ( ok(mid) )
                r = mid-1;
            else
                l = mid+1;
        }
        printf ( "%d\n" , l );
    }
    return 0;
}

C题题目链接

题意:

给一个长度为n的字符串,有q次询问,询问给两个区间问这两个区间的字符串是否完全相等。是YES,否NO。

思路:

字符串HASH。

C++代码:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int maxn = 1000010;
const int mod1 = 1e9+7;
const int mod2 = 1e9+9;
const int base1 = 131;
const int base2 = 233;


struct My_Hash
{
    ull Hash1[maxn],p1[maxn];
    ull Hash2[maxn],p2[maxn];


    void Insert( char s[] )
    {
        int len = strlen(s+1);
        Hash1[0] = 0,p1[0] = 1;
        Hash2[0] = 0,p2[0] = 1;
        for ( int i=1 ; i<=len ; i++ )
        {
            p1[i] = p1[i-1]*base1%mod1;
            p2[i] = p2[i-1]*base2%mod2;
            Hash1[i] = (Hash1[i-1]*base1%mod1+(ull)s[i])%mod1;
            Hash2[i] = (Hash2[i-1]*base2%mod2+(ull)s[i])%mod2;
        }
    }
    pair<ull,ull> GetHash( int l , int r )
    {
        ull tmp1 = Hash1[r];
        ull tmp2 = Hash2[r];
        tmp1 = ( tmp1-p1[r-l+1]*Hash1[l-1]%mod1+mod1 )%mod1;
        tmp2 = ( tmp2-p2[r-l+1]*Hash2[l-1]%mod2+mod2 )%mod2;
        return make_pair( tmp1 , tmp2 );
    }
}S;


int n,q,l1,r1,l2,r2;
char s[maxn];


int main()
{
    while( scanf ( "%d%d" , &n , &q )==2 )
    {
        scanf ( "%s" , s+1 );
        S.Insert(s);
        while( q-- )
        {
            scanf ( "%d%d%d%d" , &l1 , &r1 , &l2 , &r2 );
            pair<ull,ull>t1 = S.GetHash( l1 , r1 );
            pair<ull,ull>t2 = S.GetHash( l2 , r2 );
            printf ( "%s\n" , (t1.first==t2.first&&t1.second==t2.second)?"YES":"NO" );
        }
    }
    return 0;
}

D题题目链接

题意:

给定一个目标数x(可能为负!!!) 求若想通过0,1,2,3,。。。,n之间添加减号,使得表达式等于x的最小n为多少。

思路:

对于0 ,1,2,3,。。。,n之间添加减号的取值范围为[-n*(n+1)/2,n*(n+1)/2],首先要想凑成x,至少得要大于等于x。

第一步可以暴力,当然最好可以使用二分。

因为0,1,2,3,。。。,n之间添加减号的可以凑出[-n*(n+1)/2,n*(n+1)/2]之间的任何数,且在表达式内转变一个符号形成的差值是(两倍!!!),所以我们只要找到一个最小的n使得n*(n+1)/2>=x且(n*(n+1)/2-x)%2==0,那么这就是答案了。

C++代码:

#include<bits/stdc++.h>
using namespace std;
 
int main()
{
    int T; scanf ( "%d" , &T );
    while ( T-- )
    {
        long long x;
        scanf ( "%lld" , &x );
        if ( x<0 ) x = -x;
        long long l=0,r=100000,mid;
        while( l<=r )
        {
            mid = ( l+r )>>1;
            if ( mid*(mid+1)/2>=x )
                r = mid-1;
            else
                l = mid+1;
        }
        while ( (l*(l+1)/2-x)%2!=0 ) l++;
        printf ( "%lld\n" , l );
    }
    return 0;
}

E题题目链接

题意:

初始点为0,目标点为m(可能是负数!!!),对于一步有1/4的概率-1,1/4的概率+1,1/2的概率不变,求走n步从0到m的概率是多少,假设答案为a/b,以a*b的乘法逆元形式输出。

思路:

我们假设到达目标点包含以下操作m+i步+1,i步-1,n-m-i-i步0。(i从0到m+i+i<=n)

于是可以得到当前情况的分母部分为pow(2,n-m-i-i)*pow(4,m+i+i)

再看看分子部分,分子部分是一个组合数C(n,m+i)*C(n-m-i,i)因为总共包含三种操作固定两种自然确定最后一种,这个表达式是确定了+1的组合情况和-1的组合情况。

不断求解累加即是答案。

因为题目涉及一些乘分母,阶乘,组合数等东西,所以需要一些预处理,以及乘法逆元化。

C++代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL mod = 1e9+7;
  
LL qpow( LL a , LL b )
{
    LL res = 1;
    while ( b )
    {
        if ( b&1 ) res = res*a%mod;
        a = a*a%mod;
        b = b>>1;
    }
    return res;
}
  
LL A[100010];
LL B[100010];
LL C[100010];
LL D[100010];
LL E[100010];
LL F[100010];
  
int main()
{
    A[0] = B[0] = C[0] = 1;
    D[0] = E[0] = F[0] = 1;
    for ( int i=1 ; i<=100000 ; i++ )
    {
        A[i] = (A[i-1]*4)%mod;
        B[i] = (B[i-1]*2)%mod;
        C[i] = (C[i-1]*i)%mod;
        D[i] = qpow( C[i] , mod-2 );
        E[i] = qpow( A[i] , mod-2 );
        F[i] = qpow( B[i] , mod-2 );
    }
    int T; scanf ( "%d" , &T );
    while ( T-- )
    {
        int n,m; scanf ( "%d%d" , &n , &m );
        if ( m<0 ) m = -m;
        LL ans = 0;
        for ( int i=0 ; m+i+i<=n ; i++ )
            ans = ( ans+C[n]*D[m+i]%mod*D[i]%mod*D[n-m-i-i]%mod*E[m+i+i]%mod*F[n-m-i-i]%mod )%mod;
        printf ( "%lld\n" , ans );
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值