Educational Codeforces Round 159(Rated for Div. 2)

A. Binary Imbalance

思路

    • 只要有 01    或    10 01\;或\;10 0110 存在我们就可以一直插入 0 0 0 ,所以记录 1 1 1 的数量即可,数量等于 n n n 这不存在不同-> N O NO NO,反之-> Y E S YES YES
signed main()
{
    int T=read();
    while(T--)
    {
        re int cnt=0;
        n=read();
        scanf("%s",s+1);
        dfor(i,1,n) s[i]=='1'?++cnt:0;
        cnt==n?puts("NO"):puts("YES");
    }
    return 0;
}

B. Getting Points

思路

    • 很容易想到一天能够获得的最大收益为 t ⋅ 2 + l t\cdot2+l t2+l ,那么这样的天数是 t a s k task task 的二分之一,二分答案往左,因为工作的天数越少越好 最大收益。不过这个天数可能会是奇数,无碍,特判即可。
    • 二分完了之后也有可能还是不到 p p p ,不过此后就靠 l l l 堆出来即可。
int n,p,l,t;
signed main()
{
    int T=read();
    while(T--)
    {
        n=read(),p=read(),l=read(),t=read();
        re int d=(t<<1)+l,s=n/7+(n%7?1:0),d1=0;
        if(s&1) d1=t+l;
        s>>=1;
        re int l1=1,r1=s,ans=s;
        while(l1<=r1)
        {
            int mid=(l1+r1)>>1;
            if(mid*d>=p) ans=mid,r1=mid-1;
            else l1=mid+1;
        }
        if(ans*d>=p) writeln(n-ans);
        else if(ans*d+d1>=p) writeln(n-ans-1);
        else
        {
            p-=ans*d+d1;
            writeln(n-p/l-(p%l?1:0)-(d1?1:0)-ans);
        }
    }
    return 0;
}

C. Insert and Equalize

思路

    • 最后都要变成相同的数,在不插入 a n + 1 a_{n+1} an+1 的情况下就是变成最大的数。而单位大小都是 x x x 易得最大的 x x x 就是每一个数与最大值差值的最大公约数。将序列排序,对于 a n + 1 a_{n+1} an+1 插入的位置来说插入在第一个或者最后一个对答案的贡献是一样的,需要考虑的事插入在中间的情况。我们当然希望 a n + 1 a_{n+1} an+1 越靠近最大值越好这样对答案的贡献越小。我们可以从最大值开始往前遍历,如果两个元素的差值大于 G C D GCD GCD ,那么一定可以插入在这里。如果不是插入在中间位置,那插入在最前最后都一样,我选在最前面。
int n,a[N];
int gcd(int x,int y)
{
    return y?gcd(y,x%y):x;
}
signed main()
{
    int T=read();
    while(T--)
    {
        n=read();
        dfor(i,1,n) a[i]=read();
        if(n==1){puts("1");continue;}
        sort(a+1,a+n+1);
        re int GCD=a[n]-a[n-1];
        dforr(i,n-1,2) GCD=gcd(GCD,a[i]-a[i-1]);
        re int sum=0;
        re bool f=0;
        dforr(i,n,2)
        {
            sum+=(a[n]-a[i-1])/GCD;
            if(a[i]-a[i-1]>GCD&&!f) sum+=(a[n]-a[i])/GCD+1,f=1;
        }
        if(f) writeln(sum);
        else writeln(sum+(a[n]-a[1])/GCD+1);
    }
    return 0;
}

D. Robot Queries

分析

    • 一种很简单的思路模拟出每一步的坐标,记录下来。直接询问。很显然会 T E L TEL TEL
    • 规定 P i P_i Pi S i S_i Si m o v e move move 后的坐标,通过手模可以发现 r e v e r s e    [ l , r ] reverse\;[l,r] reverse[l,r] 之后 P 0 ∼ P l − 1 P_0\sim P_{l-1} P0Pl1 坐标不变, P r ∼ P n P_r\sim P_n PrPn 坐标不变。改变的仅仅是 P l ∼ P r − 1 P_l\sim P_{r-1} PlPr1 的坐标,而该区间的坐标改变有明显的规律关于中心对称。

思路

这题我看了官方题解代码与官方题解相似度 < 100 % <100\% <100%
值得一提的是 l a m b d a lambda lambda 的使用是我从未接触的新大陆,现在及以后将会给我带来极大的便利

    • 记录每一个 P i P_i Pi ,并用 m a p map map 对于每一个 P i P_i Pi 都记录其位置下标 i i i P i P_i Pi 视作桶,用 m a p map map 方便使用二分) 。
    • 查询三个区间 [ 0 , l − 1 ]    [ l , r − 1 ]    [ r , n ] [0,l-1]\;[l,r-1]\;[r,n] [0,l1][l,r1][r,n]
    • [ 0 , l − 1 ]    [ r , n ] [0,l-1]\;[r,n] [0,l1][r,n] 直接查询 x    y x\;y xy 即可这两个区间坐标不变 [ l , r − 1 ] [l,r-1] [l,r1] 查询 x    y x\;y xy 关于中心对称的坐标即可。由分析可得一对关于中心对称的点对为 ( P l − 1 ,    P r ) (P_{l-1},\;P_r) (Pl1,Pr)
    • 二分查询直接找大于等于左端点即可。再判断是否小于右端点。
int n,q;
char s[N];
signed main()
{
    n=read(),q=read();
    scanf("%s",s+1);
    vector<pair<int ,int > > ve;
    ve.push_back(make_pair(0,0));
    dfor(i,1,n)
    {
        int x=ve[i-1].first+(s[i]=='R')-(s[i]=='L');
        int y=ve[i-1].second+(s[i]=='U')-(s[i]=='D');
        ve.push_back(make_pair(x,y));
    }
    map<pair<int ,int > ,vector<int > > mp;
    dfor(i,0,n) mp[ve[i]].push_back(i);
    auto check = [&](pair<int ,int > p,int l,int r)
    {
        if(!mp.count(p)) return false;
        auto it=lower_bound(mp[p].begin(), mp[p].end(), l);
        return it!=mp[p].end()&&*it<=r;
    };
    while(q--)
    {
        int x,y,l,r;
        x=read(),y=read(),l=read(),r=read();
        int xx=ve[r].first+ve[l-1].first-x,yy=ve[r].second+ve[l-1].second-y;
        bool f=check({x,y},0,l-1)|check({xx,yy},l,r-1)|check({x,y},r,n);
        f?puts("YES"):puts("NO");
    }
    return 0;
}

E. Collapsing Strings

我感觉其实比D简单

思路

    • 求的就是当前字符串的后缀与每一个字符串的前缀的最大公共长度。我们可以用字典树记录前缀,询问时翻转字符串,上述所求就变成求字符串前缀的最大公共长度,前缀字典树即可解决。答案当然是总长度-所求。
int n,q,tot,cnt[N],trip[N][26];
void ins(string s)
{
    int x,p=0;
    dfor(i,0,s.size()-1)
    {
        x=s[i]-'a';
        if(!trip[p][x]) trip[p][x]=++tot;
        p=trip[p][x],++cnt[p];
    }
}
int query(string s)
{
    int x,p=0,ans=0;
    dfor(i,0,s.size()-1)
    {
        x=s[i]-'a';
        p=trip[p][x];
        ans+=cnt[p];
        if(!p) return ans;
    }
    return ans;
}
signed main()
{
    n=read();
    vector<string > ve;
    string s;
    int sum=0;
    dfor(i,1,n)
    {
        cin>>s;
        sum+=s.size(),ve.push_back(s);
        ins(s);
    }
    int ans=0;
    dfor(i,0,ve.size()-1)
    {
        reverse(ve[i].begin(),ve[i].end());
        ans+=n*ve[i].size()+sum-(query(ve[i])<<1);
    }
    write(ans);
    return 0;
}

你可能感兴趣的:(codeforces题解,算法,数据结构,c++,codeforces题解)