Codeforces #272 Div 1 简要题解

比赛总结

这次打得比上次稍微好点(其实主要是开了挂的缘故),三个题中只有A wa了一发,B和C都是fb。在正式和非正式选手中排名146名,在正式选手里排名120名

A. Dreamoon and Sums

题目链接

http://codeforces.com/contest/477/problem/A

题目大意

定义一个数字 x 是优美的,当且仅当xmodb0,xbxmodb=k,k[1,a],求所有优美的数字之和

思路

xmodb=1 ,则满足条件的 x 有:
b+1, 2b+1 ab+1

xmodb=2 ,则满足条件的 x 有:
2(b+1), 2(2b+1) 2(ab+1)

xmodb=t ,则满足条件的 x 有:
t(b+1), t(2b+1) t(ab+1)

每种情况都是一个等差数列,直接对等差数列求和即可,即 xmodb=t ,则满足条件的 x 之和为(b+1+ab+1)at2

注意乘法过程会炸掉long long int,因此要先对 at (b+1+ab+1) 之一除以2,然后对两个乘数分别取模后再做乘法

代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MOD 1000000007

using namespace std;

typedef long long int LL;

LL sum=0;
LL a,b;

int main()
{
    scanf("%I64d%I64d",&a,&b);
    for(LL t=1;t<b;t++)
    {
        LL x=(b+1+a*b+1),y=a*t;
        if(x%2==0) x/=2;
        else y/=2;
        x%=MOD,y%=MOD; //!!!!!
        sum=(sum+(x*y%MOD))%MOD;
    }
    printf("%I64d\n",sum);
    return 0;
}

B. Dreamoon and Sets

题目链接

http://codeforces.com/contest/477/problem/B

题目大意

要你构造 n 行数字,每行4个数字,数字均互不相同,使得每行四个数字中任意两个数字的gcd恰好为k,要你构造这些数字,并且要让最大的数字最小

思路

显然构造的数字应该是这样的格式
a1,1k,a1,2k,a1,3k,a1,4k
a2,1k,a2,2k,a2,3k,a2,4k
……
an,1k,an,2k,an,3k,an,4k

显然每一行的四个a均互质才行,那么最简单的构造方法就是四个a均取质数,然而这样做还不是最优解。最优解下,每行四个a里,三个是质数,一个是偶数,同样能满足互质的条件。

观察样例1和2可以构造这样的答案:
1k,2k,3k,5k
7k,8k,9k,11k
13k,14k,15k,17k
……

代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

using namespace std;

typedef long long int LL;

int main()
{
    LL a=1,b=2,c=3,d=5;
    LL n,K;
    scanf("%I64d%I64d",&n,&K);
    printf("%I64d\n",K*(5+(n-1)*6));
    for(LL i=1;i<=n;i++)
    {
        printf("%I64d %I64d %I64d %I64d\n",a*K,b*K,c*K,d*K);
        a+=6,b+=6,c+=6,d+=6;
    }
    return 0;
}

C. Dreamoon and Strings

题目链接

http://codeforces.com/contest/477/problem/C

题目大意

给你一个字符串,问这个字符串删去1,2,3… |S| 次后,最多能包含多少个 T

思路

f[i][j]表示 S 串前i个字符,删去 j 次后最多能包含多少个T串。在求所有 f[i][] 前,我们先找出最大的 p ,使得[p,i]区间删去若干字符后可以匹配上一个 T 串。假设这个区间要删去t个字符。则一些 f[i][j] 可以从 f[p1][jt] 转移而来,而另一些则只能从 f[i1][j] 转移而来,具体看代码

代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MAXN 2100

using namespace std;

typedef long long int LL;

int f[MAXN][MAXN];
char S[MAXN],T[MAXN];
int lenS,lenT;

int main()
{
    scanf("%s%s",S+1,T+1);
    lenS=strlen(S+1);
    lenT=strlen(T+1);
    for(int i=lenT;i<=lenS;i++)
    {

        bool flag=true;
        int p1,p2;
        for(p1=i,p2=lenT;p2>=1&&p1>=1;p1--)
            if(S[p1]==T[p2]) p2--;
        p1++; //[p1,i]段构成一个T串
        if(!p2)
        {
            for(int j=0;j<=i;j++) //删除j次字符
                if(j-(i-p1+1-lenT)>=0&&j-(i-p1+1-lenT)<=p1-1) //!!!!!!
                    f[i][j]=f[p1-1][j-(i-p1+1-lenT)]+1;
        }
        for(int j=0;j<=i-1;j++)
            f[i][j]=max(f[i][j],f[i-1][j]);
    }
    for(int j=0;j<=lenS;j++)
        printf("%d ",f[lenS][j]);
    printf("\n");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值