Codeforces Round #515 (Div. 3) 解题报告(A~E)

题目链接:http://codeforces.com/contest/1066

A题:
题意:Vova想坐火车从1点到L点,在路上v的整数倍的点上分布着灯笼,而在路上从l到r处停着别的火车,它挡着Vova的视线使他看不到灯笼。给定L,v,l,r求Vova能看到的灯笼数。
分析:从1到x上所有的灯笼数量为x/v个。则路上所有的灯笼数为 L/v个,被挡住的则为 r/v - (l-1)/v 个,相减即为答案。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define closeio std::ios::sync_with_stdio(false)
using namespace std;
typedef long long ll;
int t,L,v,l,r;
int main()
{
    cin>>t;
    while(t--)
    {
        scanf("%d%d%d%d",&L,&v,&l,&r);
        int ans = L / v;
        ans = ans - (r/v - (l-1)/v);
        cout<<ans<<endl;
    }
    return 0;
}
View Code

B题:

题意:Vova的房子由从1到n的房间组成。这些房间从左到右排成一排相互连通,有的房间放着火炉。火炉工作时可以温暖以其所在的第pos个房间为中心, [posr+1;pos+r1]这个区间的所有房间。现在给定n个房间的火炉信息和r,求最少需要开几个火炉可以使整个房子都温暖。

分析:贪心,例如对于起始点1来说,在能覆盖到点1的所有火炉中,我们选最靠后的那一个。之后的每次处理就是把新的第一个没有覆盖到的点看成起始点继续贪心。这样可以保证每次选择覆盖的区间尽可能大。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define closeio std::ios::sync_with_stdio(false)
using namespace std;
const int maxn = 20005;
int n,r,a[maxn],ans;
bool flag;
int main()
{
    int i,j;
    while(cin>>n>>r)
    {
        flag = true;
        memset(a,0,sizeof(a));
        for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
        int pos = 0;//pos指向最后放置的炉子的位置
        for(i = r;i >= 1; i--)
        {
            if(a[i] == 1) 
            {
                pos = i;
                ans = 1;
                break;    
            }
        }
        if(i == 0) flag = false;
        while(pos + r - 1 < n && flag)//pos+r-1是当前所放最后一个炉子能覆盖的最右点 
        {
            for(i = pos+r*2-1;i >= pos; i--)//pos+r*2-1是下一个炉子可以存在的位置的最远点,注意这里值可能比1000大,所以数组范围开大些 
            {
                if(a[i] == 1)
                {
                    if(i == pos) //pos后的长度为2*r-1的区间没有炉子 
                        flag = false;
                    else
                    {
                        pos = i;
                        ans ++;
                    }
                    break;
                }
            }
        }
        printf("%d\n",flag?ans:-1);
    }
    return 0;
}
View Code

C题:

题意:你有一个书架,可以对它进行三种操作:L id表示把编号为id的书放在所有书的最左边。R id表示表示把编号为id的书放在所有书的最右边。? id表示询问编号为id的书距离整个书列的最外侧(左侧或右侧)的最小值。

分析:题目给定的操作数量和id的范围均为2*1e5,所以可以开一个2*1e5大小的数组存放每本书的位置。我们可以设置posx和posy分别指向书列的左右两侧的位置,当有书放进来时改变posx和posy的值并赋给a[id],查询操作如上所述。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define closeio std::ios::sync_with_stdio(false)
using namespace std;
const int maxn = 200005;
int a[maxn],id,q,posx,posy;
char c;
int main()
{
    cin>>q;
    posx = posy = 0;
    memset(a,0,sizeof(a));
    while(q--)
    {
        getchar();
        scanf("%c %d",&c,&id);
        if(c == 'L')
        {
            a[id] = posx--;
        }
        if(c == 'R')
        {
            a[id] = ++posy;
        }
        if(c == '?')
        {
            cout<<min(a[id] - posx - 1,posy - a[id])<<endl;
        }
    }
    return 0;
}
View Code

D题:

题意:这个题的题意很蛋疼QAQ不想扯,出题人就是想通过题意把你带跑。其实是最简单的一个题,就是给你n个物品,让你放进m个容量为k的箱子里,要求是只能取从最后一个开始连续的物品,问最多装几个物品。

分析:直接从后往前扫一遍得出答案。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define closeio std::ios::sync_with_stdio(false)
using namespace std;
const int maxn = 200005;
int n,m,k,ans,pos;
int a[maxn],b[maxn];
int main()
{
    int i,j;
    while(cin>>n>>m>>k)
    {
        for(i = 1;i <= n; i++)
            scanf("%d",&a[i]);
        for(i = 1;i <= m;i++)
            b[i] = k;
        j = m;
        ans = 0;
        for(i = n;i >= 1; i--)
        {
            if(b[j] >= a[i])
            {
                b[j] -= a[i];
                ans ++;
            }
            else
            {
                if(j > 1)
                {
                    b[--j] -= a[i];
                    ans ++;
                }
                else
                {
                    break;
                }
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}
View Code

E题:

题意:给你长为n的二进制数a和长为m的二进制数b,每次操作把a&b的十进制结果累加起来,然后把b往右移一位直到b为0。最后结果对998244353998244353取余。

分析:这个题还是非常不错的一道题的。对于a的每一个为1的二进制位,其对答案的贡献就是所有a&b操作后a的这一位仍为1的次数再乘上这一位为1对应的十进制数。所以我们预处理一下pw数组存放二进制位为1对应的10进制数取余,sum数组则存放前缀和,sum[i]即为第i位及其之前b里有几个1。考虑到n与m可能不相等,我们预处理一下a,b使其长度一致。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define closeio std::ios::sync_with_stdio(false)
using namespace std;
typedef long long ll;
const ll mod = 998244353;
const int maxn = 200005;
ll n,m,pw[maxn],sum[maxn];
string a,b;
void init_ab()
{
    if(n > m) b = string(n-m,'0') + b;
    else if(m>n) a = string(m-n,'0') + a;
    
    memset(sum,0,sizeof(sum));
    memset(pw,0,sizeof(0));
    
    int i,j;
    pw[0] = 1;
    for(i = 1;i < maxn; i++) pw[i] = pw[i-1] * 2 % mod;//预处理pw数组 
}
int main()
{
    int i,j,k;
    while(cin>>n>>m)
    {
        ll ans = 0;
        closeio;
        a.clear();
        b.clear();
        cin>>a>>b;
        init_ab();
        k = max(n,m);
        sum[0] = b[0]=='1';
        for(i = 1;i < k;i++)
            sum[i] = sum[i-1] + (b[i] == '1');//sum[i]存放第i位及其之前b里有多少位为1
        for(i = 0;i < k;i ++)
        {
            if(a[i]-'0')//a[i]为1才对答案有贡献 
            {
                ans = (ans + pw[k-i-1] * sum[i] % mod) % mod;//所有a&b操作后a的这一位仍为1的次数再乘上这一位为1对应的十进制数 
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/chdforestsea/p/9788956.html