Codeforces Round #505 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Final) (ABCD总结)

一上一下的蓝名。。何时能稳定下来。。

第一次终测挂了一道题排名居然还上升了。。。总之这一场就是fst+hack专场吧。。。

A:给你一个字符串,求是否有一个字母出现超过2次。(注意:n=1要特判yes,否则WA)出题人还算良心卡掉了没判1的情况,不然就好玩了。。。

B:这是本套题最坑的题,给你n对数,让你求是否存在一个数,对于每对数,都存在1个数或者2个数能整除他。

n为1.5e5,a[i]高达2e9。所以想提前筛因子是不可能的。

hack点1:x,y要加入答案数组中。有一些人初始化只加了x和y的非1因子,却没加x和y,最终fst test 14

hack点2:有些人企图用set等保存所有数的因子再O(n)判断,然后 fst tle 45。数高达2e9,如果每一对数都拥有很多个因子,显然复杂度再乘上一个n就瞬间爆炸。

正解(我看到的一个比较好的解法)应该是 先预处理每一对数的LCM。(因为答案肯定是这些lcm的某个因子),然后对每一对数的lcm求gcd。这就是初始的答案ans。然后再O(n)扫一遍,如果这一对数有能整除ans的数就不管,否则就从gcd(ans,a[i])和gcd(ans,b[i])中取一个最大的替换ans。总时间复杂度为O(nlogn)。

C:给你一个wb串,你可以选任意一个位置,将这个位置两边的串翻转再接起来。问你最后最长的wbwbw这样间隔的长度是多长。这个题比较偏向思维。在纸上画一下发现一次操作就相当于在这个串后面再接上这个串。于是把这个串再复制一遍接到后面,然后就求一个最大的wbwb串即可。注意:

hack点1:只有w或b的时候答案为1,有的人没判被我hack了一个

hack点2:不要想着去模拟,我造了个wwwwb有个代码答案是4,然后就被我hack了。光判情况能过终测的概率太小了。

hack点3:如果按照我这个思路,最后答案一定不要忘了和n取最小值!!!我刚开始忘了,通过比赛数据后突然想起来了立马改了,最后才过了终测。

D:这道题也比较坑。给你一些数,求是否能用这些数构成二叉搜索树,而且每个边连接的两个节点gcd大于1。

有9页的终测挂在了这组数据:

4

2 3 5 30

原因就是没想着构造树或者构造的时候只考虑了整体的gcd数或者构造方法不正确。还有一些未知的原因代码太长我就没看。。。

其实记忆化搜索即可(区间dp)。

dp[l][r][2]。若第三维为0,表示区间[l,r] 作为上一个节点的左孩子。1就表示[l,r] 作为上一个节点的右孩子。然后预处理能够连接的下标。

代码:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=710;
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int n,m,k;
int y[maxn][maxn];
int c[maxn],dp[maxn][maxn][2];
int ans,ct,cnt,tmp,flag;
bool jud(int l,int r,int id)
{
    if(l>r)return 1;
    int &ans=dp[l][r][id];
    if(ans+1) return ans;
    ans=0;
    int up=id?l-1:r+1;
    for(int i=l;i<=r;i++)
    if(y[i][up]&&jud(l,i-1,0)&&jud(i+1,r,1))
    return ans=1;
    return ans;
}
int main()
{
    int T,cas=1;
    while(scanf("%d",&n)!=EOF)
    {
        memset(dp,-1,sizeof(dp));
        for(int i=0;i<n;i++)
        {
        scanf("%d",&c[i]);
        }
        for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        if(gcd(c[i],c[j])>1){
            y[i][j]=1;
        }
        for(int i=0;i<n;i++)
        if(jud(0,i-1,0)&&jud(i+1,n-1,1))
        return puts("Yes"),0;
        puts("No");
        //printf("%d\n",ans);
        //if(flag) puts("Yes"); else puts("No");
    }
    return 0;
}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值