Codeforces Round #515 (Div. 3) ABCDEF比赛总结

做了4题,ABCE。感觉不是很满意。1、D题题意读不懂,刚开始想法对了,但是可惜题意读错了一直WA。2、F题没来得及看。

感觉本场比赛的题目还算可以。

A:三行系列。读懂题意就能做。因为只除去了中间的部分。但是感觉放在div3的A题还是稍微难了点。

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=200010;
int n,m,k,v;
int a[maxn],sum[maxn];
int c[maxn];
int ans,ct,cnt,tmp,flag;
char s[maxn];
int main()
{
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d%d",&n,&m,&k,&v);
        ans=n/m;
        tmp=v/m-(k-1)/m;
        printf("%d\n",ans-tmp);
    }
    return 0;
}

B:感觉这题有点坑。给你一01序列,长度为n,再给你r,1的地方可以种洒水器,范围是(pos-r+1,pos+r-1)。pos是为1的位置。

问你至少种多少洒水器可以覆盖1~n。如果不能输出-1。直接模拟即可。不过细节挺多,样例给的还算好。注意-1。

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=200010;
int n,m,k,v;
int a[maxn],sum[maxn];
int c[maxn];
int ans,ct,cnt,tmp,flag;
char s[maxn];
int main()
{
    int T,cas=1;
    scanf("%d%d",&n,&m);
    ans=-1;
    for(int i=1;i<=n;i++)
    {scanf("%d",&a[i]);if(a[i])ans=0;}
    int r=0;
    int i=1;
    while(i<=n)
    {
        int tmp=ans,fg=0;
        for(;i<=n;i++)
        if(a[i]&&i-m+1<=r+1){fg=i;}
        else if(a[i]&&i-m+1>r+1) break;
        if(fg) ans++;
        r=fg+m-1;
        i=fg+1;
        if(r>=n) break;
        if(!fg) {ans=-1;break;}

    }
    printf("%d\n",ans);
    return 0;
}

C:有一个书架(只有一层),m次操作,每次操作为 一个字符+x  如果字符为'L'或'R',则放上编号为x的书。放在最左边或最右边。如果是'?' x 则查询至少移除多少本书才能使编号为x的书位于最左边或最右边。

不知道别人思路怎么样,我的第一感觉就是树状数组。从中间分开,200005和200006开始分别往左右放,询问的时候查询啷个值比较一下就行了。

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=400010;
int n,m,k,v;
int a[maxn],mp[maxn];
int c[maxn];
int ans,ct,cnt,tmp,flag;
char s[maxn];
int lb(int x){return x&(-x);}
void add(int i,int v)
{
    while(i<maxn)
    {
        c[i]+=v;
        i+=lb(i);
    }
}
int query(int i)
{
    int ans=0;
    while(i>0)
    {
        ans+=c[i];
        i-=lb(i);
    }
    return ans;
}
int main()
{
    int T,cas=1;
    scanf("%d",&n);
    memset(c,0,sizeof(c));
    int l=200005,r=200006;
    for(int i=0;i<n;i++)
    {
        scanf("%s %d",s,&m);
        if(s[0]=='L') {mp[m]=l--;add(l+1,1);}
        else if(s[0]=='R') {mp[m]=r++;add(r-1,1);}
        else
        {
            ans=min(query(mp[m]-1),query(400008)-query(mp[m]));
            printf("%d\n",ans);
        }
    }
      //  if(flag) puts("Yes"); else puts("No");
    return 0;
}

D:这题题意很迷啊。我感觉题意说的有问题。实际上就是给你n个玩具,m个箱子,每个箱子容量为k,每个玩具体积为a[i]。

从第一个玩具开始依次装,如果能把所有玩具装进去就停止。否则到了一个玩具,已经没有足够的箱子容量装了的话,他就会把现在所有箱子里最早装的玩具扔掉。直到当前玩具能装进去。问最后箱子里一共能装多少玩具。

思路:如果题意像我说的这么简单,那么这道题就可以当做A题了(然而出题人非要整的花里胡哨乱七八糟看不懂的)。显然只需要从后往前贪心装,装不下就停。这时装的玩具数量就是答案。

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=400010;
ll n,m,k,v;
ll a[maxn],sum[maxn];
ll c[maxn],ed[maxn],be[maxn];
ll ans,ct,cnt,tmp,flag;
char s[maxn];
int main()
{
    int T,cas=1;
    scanf("%lld%lld%lld",&n,&m,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
    }
    for(int i=0;i<=max(2*n,2*m);i++)
    c[i]=k;
    int box=0,l=1,ans=0,tmp=0,st=0,aa=0;
    for(int i=n;i>=1;i--)
    {
        if(c[box]>=a[i])
        {
            c[box]-=a[i];
            be[i]=box;
            tmp++;
            ans=max(ans,tmp);
        }
        else if(box+1<m)
        {
            box++;
            c[box]-=a[i];
            be[i]=box;
            tmp++;
            ans=max(ans,tmp);
        }
        else break;
    }
    printf("%d\n",ans);
      //  if(flag) puts("Yes"); else puts("No");
    return 0;
}

E:

给你两个二进制01串,长度分别为n,m(n,m<=2e5)。求第一个串&第二个串的十进制和。每&一次,就去掉第二个串的最后一位继续&,直到第二个串为空。

观察可以发现,只需要维护一个2的n次方的前缀和就行了。m>n时,第二个串的前m-n位一定是每一个1都会与第一个串每一个1&一次,后面的n位就依次往后了。m<n时,第二个串每个1就只有机会&第一个串中后n-m个1了。可以画图理解一下。(题意说清楚就比D题简单了)

我用的快速幂,其实可以不用的,不用就可以O(n)解决。

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=400010;
const ll mo=998244353;
ll n,m,k,v;
ll a[maxn],sum[maxn];
ll c[maxn],ed[maxn],be[maxn];
ll ans,ct,cnt,tmp,flag;
char s[maxn],t[maxn];
ll power(ll a,ll n)   //a的n次方mod
{
    ll ans=1;
    a=a%mo;
    while (n)
    {
        if(n&1) ans=(ans*a)%mo;
        n>>=1;
        a=(a*a)%mo;
        }
    return ans;
}
int main()
{
    int T,cas=1;
    scanf("%lld%lld",&n,&m);
    scanf("%s%s",s,t);
    sum[n+1]=0;ans=0;
    for(int i=n-1;i>=0;i--)
    {
        if(s[i]=='0') sum[i]=sum[i+1];
        else sum[i]=(sum[i+1]+power(2,n-i-1))%mo;
    }
    if(m>n)
    {
        for(int i=0;i<m-n;i++)
        if(t[i]=='1'){
        ans=(ans+sum[0])%mo;
        }
        for(int i=m-n,j=0;i<m;i++,j++)
        if(t[i]=='1'){
        ans=(ans+sum[j])%mo;
        }
    }
    else
    {
        for(int i=0,j=n-m;i<m;i++,j++)
        if(t[i]=='1'){
        ans=(ans+sum[j])%mo;
        }
    }

    printf("%lld\n",ans);
      //  if(flag) puts("Yes"); else puts("No");
    return 0;
}

F:(这道题在区域赛上可能算个签到题吧。。。)

给你二维平面的n个点(n<=2e5) 以每个点的max(x,y)分层,你从(0,0)点开始走,每一步只能走上下左右长度为1,你要先走到第一层,走过第一层的所有点后,才能走第二层,以此类推,求走完最后一层的所有点,最少需要多少步。

由于要分层,就用一个vector存一下每一层的点。观察发现每一层最左上的点到最右下的点,一定有一条路径可以经过这一层的所有点。显然这就是走遍这一层最短步数路线。于是每一层的点,按x从小到大排序,x相同按y从大到小排序。画个图一下就懂了。于是dp方程也有了。设dp[i][0]为走完第i层且位于这一层的最左上的点的最少步数。则v[i][]表示第i层的所有点(排序后的)

t1和t2为离散化后第i-1和第i层的点的编号。于是有

dp[i][0]=min(dp[i-1][1]+dist(v[t1].back(),v[t2].back()),dp[i-1][0]+dist(v[t1][0],v[t2].back()))+dist(v[t2][0],v[t2].back());

同样,设dp[i][1]为走完第i层且位于这一层的最右下的点的最少步数。则有

dp[i][1]=min(dp[i-1][1]+dist(v[t1].back(),v[t2][0]), dp[i-1][0]+dist(v[t1][0],v[t2][0]))+dist(v[t2][0],v[t2].back());

最后min(dp[最后一层][0],dp[最后一层][1])就是答案。

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3fLL
using namespace std;
const int maxn=1e6+10;
map<int,int>mp;
int cnt,n;
vector<pair<ll,ll> >v[maxn];
ll dp[maxn][2];
ll dist(pair<ll,ll> a,pair<ll,ll> b)
{
    return abs(a.first-b.first)+abs(a.second-b.second);
}
bool cmp(pair<ll,ll> a,pair<ll,ll> b)
{
    return a.first<b.first||(a.first==b.first&&a.second>b.second);
}
int main()
{
    scanf("%d",&n);
    vector<ll>vv;
    cnt=0;
    for(int i=1;i<=n;i++)
    {
        ll l,r;
        scanf("%lld%lld",&l,&r);
        ll c=max(l,r);
        if(mp[c]==0)
        {
            mp[c]=++cnt;
            vv.push_back(c);
        }
        v[mp[c]].push_back(make_pair(l,r));
    }
    vv.push_back(0);
    mp[0]=++cnt;
    v[cnt].push_back(make_pair(0,0));
    sort(vv.begin(),vv.end());
    for(int i=0;i<vv.size();i++)
    dp[i][0]=dp[i][1]=inf;
    dp[0][0]=dp[0][1]=0;
    for(int i=1;i<vv.size();i++)
    {
        int t1=mp[vv[i-1]];
        int t2=mp[vv[i]];
        sort(v[t2].begin(),v[t2].end(),cmp);
        dp[i][0]=min(dp[i-1][1]+dist(v[t1].back(),v[t2].back()),
                     dp[i-1][0]+dist(v[t1][0],v[t2].back()));
        dp[i][0]+=dist(v[t2][0],v[t2].back());

        dp[i][1]=min(dp[i-1][1]+dist(v[t1].back(),v[t2][0]),
                     dp[i-1][0]+dist(v[t1][0],v[t2][0]));
        dp[i][1]+=dist(v[t2][0],v[t2].back());
    }
    printf("%lld\n",min(dp[vv.size()-1][0],dp[vv.size()-1][1]));
}

猜你喜欢

转载自blog.csdn.net/LSD20164388/article/details/83042178