AtCoder Beginner Contest 177


ABCDEF

( √:做出; ●:尝试未做出; ○:已补题 )


题目地址:https://atcoder.jp/contests/abc177



A Don’t be late

题意:水题

思路

代码

#define DIN freopen("input.txt","r",stdin);
#define DOUT freopen("output.txt","w",stdout);
#include <bits/stdc++.h>
#include <cstdio>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
using namespace std;
typedef long long LL;
typedef std::vector<int> VI;
typedef std::pair<int,int> P;
int read()
{
    int x=0,flag=1; char c=getchar();
    while((c>'9' || c<'0') && c!='-') c=getchar();
    if(c=='-') flag=0,c=getchar();
    while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return flag?x:-x;
}

int main()
{
    int d=read(),t=read(),s=read();
    puts(s*t>=d?"Yes":"No");

    return 0;
}



B Substring

题意:水题

思路

代码

#define DIN freopen("input.txt","r",stdin);
#define DOUT freopen("output.txt","w",stdout);
#include <bits/stdc++.h>
#include <cstdio>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
using namespace std;
typedef long long LL;
typedef std::vector<int> VI;
typedef std::pair<int,int> P;
int read()
{
    int x=0,flag=1; char c=getchar();
    while((c>'9' || c<'0') && c!='-') c=getchar();
    if(c=='-') flag=0,c=getchar();
    while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return flag?x:-x;
}

char s[1005],t[1005];

int main()
{
    scanf("%s %s",s+1,t+1);
    int ns=strlen(s+1),nt=strlen(t+1);
    int ans=1e9;
    for(int i=1;i+nt-1<=ns;i++)
    {
        int cnt=0;
        for(int j=i,k=1;k<=nt;k++,j++)
            if(s[j]!=t[k])
                cnt++;
        ans=min(ans,cnt);
    }
    cout<<ans;

    return 0;
}



C Sum of product of pairs

题意:水题

思路:计算一个后缀和就行了

代码

#define DIN freopen("input.txt","r",stdin);
#define DOUT freopen("output.txt","w",stdout);
#include <bits/stdc++.h>
#include <cstdio>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
using namespace std;
typedef long long LL;
typedef std::vector<int> VI;
typedef std::pair<int,int> P;
int read()
{
    int x=0,flag=1; char c=getchar();
    while((c>'9' || c<'0') && c!='-') c=getchar();
    if(c=='-') flag=0,c=getchar();
    while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return flag?x:-x;
}

const LL M=1e9+7;
const int maxn=2e5+5;
LL A[maxn];

int main()
{
    int n=read();
    REP(i,1,n) A[i]=A[i-1]+read();
    LL ans=0;
    for(int i=1;i<n;i++)
    {
        ans=(ans+(A[n]-A[i])%M*(A[i]-A[i-1]))%M;
    }
    cout<<ans;

    return 0;
}



D Friends

题意:并查集水题。

思路:算完并查集之后找到最大的那一个集合,输出集合大小即可。

代码

#define DIN freopen("input.txt","r",stdin);
#define DOUT freopen("output.txt","w",stdout);
#include <bits/stdc++.h>
#include <cstdio>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
using namespace std;
typedef long long LL;
typedef std::vector<int> VI;
typedef std::pair<int,int> P;
int read()
{
    int x=0,flag=1; char c=getchar();
    while((c>'9' || c<'0') && c!='-') c=getchar();
    if(c=='-') flag=0,c=getchar();
    while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return flag?x:-x;
}

const int maxn=2e5+5;
int far[maxn],t[maxn];

int findd(int x){return x==far[x]?x:far[x]=findd(far[x]);}
void unite(int x,int y){far[findd(x)]=findd(y);}

int main()
{
    int n=read(),m=read();
    REP(i,1,n) far[i]=i;
    while(m--)
    {
        int a=read(),b=read();
        unite(a,b);
    }
    REP(i,1,n) t[findd(i)]++;
    cout<<*max_element(t+1,t+n+1);

    return 0;
}



E Coprime

题意:给你 N( 2 ≤ N ≤ 1 0 6 2\le N \le 10^6 2N106) 个数字(数字大小不超过 1 0 6 10^6 106),有三种可能性:

  • 这 N 个数字两两互质;
  • 这 N 个数字总体的最大公因数等于 1;
  • 其它情况

现在你需要判断是哪种情况。

思路:数据量非常大,肯定不能暴力。注意到数字大小限制,如果两个数字不互质,那么它们一定有共同的质因子,而 1000000 以内的质因数不会特别多,根据抽屉原理,如果数据量很大的时候,我们很快就能找到两个不互质的数。所以对于第一种情况,做法就是对每个数分解质因数,然后统计哪些质因数出现过,然后标记出来,如果之前这个质因数已经出现过,那么就可以排除第一种情况了。

对于第二种情况那就非常简单,直接扫一遍计算即可。

代码

#define DIN freopen("input.txt","r",stdin);
#define DOUT freopen("output.txt","w",stdout);
#include <bits/stdc++.h>
#include <cstdio>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
using namespace std;
typedef long long LL;
typedef std::vector<int> VI;
typedef std::pair<int,int> P;
int read()
{
    int x=0,flag=1; char c=getchar();
    while((c>'9' || c<'0') && c!='-') c=getchar();
    if(c=='-') flag=0,c=getchar();
    while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return flag?x:-x;
}

const int maxn=1e6+5;
bool isprime[maxn];
int prime[maxn],cnt,a[maxn],n;

bool pairwise()
{
    set<int> t;
    REP(i,1,n)
    {
        int x=a[i];
        for(int j=1;prime[j]*prime[j]<=x;j++)
            if(x%prime[j]==0)
            {
                if(t.count(prime[j])) return 0;
                t.insert(prime[j]);
                while(x%prime[j]==0) x/=prime[j];
            }
        if(x>1)
        {
            if(t.count(x)) return 0;
            t.insert(x);
        }
    }
    return 1;
}

bool setwise()
{
    int x=a[1];
    REP(i,2,n) x=__gcd(x,a[i]);
    return x==1;
}

int main()
{
    REP(i,2,1000000) isprime[i]=1;
    for(int i=2;i<=10000;i++)
        if(isprime[i])
            for(int j=i*i;j<=1000000;j+=i)
                isprime[j]=0;
    for(int i=2;i<=1000000;i++)
        if(isprime[i])
            prime[++cnt]=i;

    n=read();
    REP(i,1,n) a[i]=read();
    if(pairwise()) puts("pairwise coprime");
    else if(setwise()) puts("setwise coprime");
    else puts("not coprime");

    return 0;
}



F I hate Shortest Path Problem

题意:一个 (H+1)*W( 1 ≤ H , W ≤ 2 × 1 0 5 1\le H,W\le 2\times10^5 1H,W2×105) 的网格,只用考虑上面 H*W 的部分,如果某个格子没有挡板,那么它可以往下或者往右走,如果有挡板,那么只能往右走。现在对于每一行,给出 A i A_i Ai B i B_i Bi ,表示 [ A i , B i ] [A_i,B_i] [Ai,Bi] 这个区间内的格子有挡板,然后你需要回答的问题是:对于每一个 i ∈ [ 1 , H ] i\in [1,H] i[1,H] ,如果理性的选择第一行的起始位置,最少要经过多少步,才可以到达第 i + 1 i+1 i+1 行的任意一个位置?如果不可能到达,则输出 -1 。

思路:对于这种复杂问题肯定是要想办法一点一点分析的。我们用一个数组表示在某次处理中,每个位置的最优解,然后首先考虑对于有挡板的这些格子,可以把它们都 +inf,因为它们不能往下走,所以它们下面那些点一定没有左边的点更优(因为就算可以也是要从左边那些走过来),所以直接 +inf 对答案没有影响;然后有一个点要特殊考虑,就是 B i + 1 B_i+1 Bi+1 那个点,它可以从 [ 1 , B i ] [1,B_i] [1,Bi] 中的某个最优点转移过来,但是只用考虑这个最优点,因为它右边的点通过这种方法转移的话,一定没有它更优;然后剩下的就是所有点 +1,代表往下走一格。

然后考虑如何维护那个特殊点的处理(其他两种线段树很好解决),维护方法就是再建一个线段树,维护 a n s i − i ans_i-i ansii 的值,因为处理特殊点的时候,转移要考虑距离,所以维护这个线段树的话,取其中的最小值 m i n x minx minx,每次就可以拿 m i n x + r minx+r minx+r(代入后就是 a n s i + r − i ans_i+r-i ansi+ri)去和 a n s r ans_r ansr 比较看是否需要更新。

代码

#define DIN freopen("input.txt","r",stdin);
#define DOUT freopen("output.txt","w",stdout);
#include <bits/stdc++.h>
#include <cstdio>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
using namespace std;
typedef long long LL;
typedef std::vector<int> VI;
typedef std::pair<int,int> P;
int read()
{
    int x=0,flag=1; char c=getchar();
    while((c>'9' || c<'0') && c!='-') c=getchar();
    if(c=='-') flag=0,c=getchar();
    while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return flag?x:-x;
}

const LL inf=1e9;
template <class T>
struct segment_tree_min
{
    #define chl (k<<1)
    #define chr (k<<1|1)
    #define mid ((l+r)>>1)
    T *t,*tag;
    int n;

    segment_tree_min(int n) {t=new T[n<<2](); tag=new T[n<<2](); this->n=n;}

    void push_up(int k) {t[k]=min(t[chl],t[chr]);}

    void push_down(int k,int l,int r)
    {
        if(!tag[k]) return;
        t[chl]+=tag[k]; t[chr]+=tag[k];
        tag[chl]+=tag[k]; tag[chr]+=tag[k]; tag[k]=0;
    }

    void build(int k,int l,int r,T *a)
    {
        if(l>r) return;
        if(l==r) {t[k]=a[l]; return;}
        build(chl,l,mid,a); build(chr,mid+1,r,a);
        push_up(k);
    }
    void build(T *a) {build(1,1,n,a);}

    void update_add(int k,int l,int r,int ll,int rr,T x)
    {
        if(l>rr || ll>r) return;
        if(l>=ll && r<=rr) {t[k]+=x; tag[k]+=x; return;}
        push_down(k,l,r);
        update_add(chl,l,mid,ll,rr,x); update_add(chr,mid+1,r,ll,rr,x);
        push_up(k);
    }
    void update_add(int ll,int rr,T x) {update_add(1,1,n,ll,rr,x);}

    T query(int k,int l,int r,int ll,int rr)
    {
        if(l>rr || ll>r) return inf*10000;  // attention!
        if(l>=ll && r<=rr) return t[k];
        push_down(k,l,r);
        return min(query(chl,l,mid,ll,rr),query(chr,mid+1,r,ll,rr));
    }
    T query(int ll,int rr) {return query(1,1,n,ll,rr);}
};

const int maxn=2e5+5;
int H,W,A[maxn],B[maxn];

int main()
{
    H=read(),W=read();
    REP(i,1,H) A[i]=read(),B[i]=read();
    segment_tree_min<LL> t1(W),t2(W);
    REP(i,1,W) t2.update_add(i,i,-i);

    REP(i,1,H)
    {
        int r=B[i]+1;
        if(r<=W)
        {
            LL minx=t2.query(1,B[i]);
            LL now=t1.query(r,r);
            if(now>minx+r)
            {
                t1.update_add(r,r,minx+r-now);
                t2.update_add(r,r,minx-t2.query(r,r));
            }
        }
        t1.update_add(A[i],B[i],inf);
        t2.update_add(A[i],B[i],inf);
        t1.update_add(1,W,1);
        t2.update_add(1,W,1);

        LL x=t1.query(1,W);
        if(x>=inf) puts("-1");
        else printf("%lld\n",x);
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值