Codeforces Round 895 (Div. 3) (A~G)

A. Two Vessels

题意:你有两个无限容量杯子A,B,分别装了a,b升的水,此外你还有一个容量为c的杯子C,你可以将一杯的水先倒入C中,再倒入另一个杯子,问你最少需要操作几次能使得A B杯的水量相同。

解析:初始两杯相差d升,其实就是问你 d对2*c向上取整。

cpp 复制代码
void solve()
{
    int a,b,c;
    scanf("%d%d%d",&a,&b,&c);
    c*=2;
    int d=abs(a-b);
    if(d==0)
    {
        printf("0\n");
        return;
    }
    printf("%d\n",(d-1)/c+1);
}

B. The Corridor or There and Back Again

题意:有一个无限长的房间,有n个陷阱,每个陷阱有两个参数d,s表示该陷阱只有你到达d房间之后再经过s秒激活,问你最多能到多远且能安全返回。

解析:其实我们考虑一个陷阱,对于该陷阱,我们最多能再走(s-1)/2个房间(安全来回),因此对于每一个陷阱,计算能到的最远房间与答案取min即可。

cpp 复制代码
void solve()
{
    int n,ans=1e9;//初始化答案
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int d,s;
        scanf("%d%d",&d,&s);
        ans=min(ans,d+(s-1)/2);
    }
    printf("%d\n",ans);
}

C. Non-coprime Split

题意:给定L,R,问你是否存在两个数a,b,满足a+b在[L,R]中且gcd(a,b)不等于1。

解析:1.其实发现只要区间长度>=2,那么肯定有偶数,因此我们设立a=2,只要在区间中找到一个偶数,两者gcd肯定是2,即为可行解。 2.如果L=R,那么只要L存在非1的因子,那么就是有解,因此假设x是L的因子,那么L/x就是另一部分,那么两者gcd就是x,且相加是L。

cpp 复制代码
void solve()
{
    int L,R,a=2;
    scanf("%d%d",&L,&R);
    for(int i=L-2;i<=R-2;i++)
    {
        if(i%2==0&&i>0)//需要正整数
        {
            printf("2 %d\n",i);
            return;
        }
    }
    if(L==R)
    {
        for(int i=2;i<=L/i;i++)//寻找因子
        {
            if(L%i==0)
            {
                printf("%d %d\n",i,L-i);
                return;
            }
        }
    }
    printf("-1\n");
}

D. Plus Minus Permutation

题意:给定n,x,y,定义价值为(p1⋅x+p2⋅x+...+p⌊n/x⌋⋅x)−(p1⋅y+p2⋅y+...+p⌊n/y⌋⋅y),p表示n的排列,问你重新排列1~n,使得价值最大化,输出这个价值。

解析:前一半有⌊n/x⌋个数,后一半有⌊n/y⌋个数,那么我们优先选择n,n-1,n-2....填充前面⌊n/x⌋个位置,后一半选择1,2,3...填充,但其中其实可能有重复的位置,重复位置肯定就等价抵消了,计算非重复的即可,重复的个数就是n除以两者的最小公倍数。

cpp 复制代码
void solve()
{
    ll n,x,y;
    scanf("%lld%lld%lld",&n,&x,&y);
    ll k=x*y/__gcd(x,y);//最小公倍数
    ll w=n/k;//重复的个数
    ll s1=n/x-w,s2=n/y-w;//前一般有s1个数,后一半有s2个数
    ll a=s1*n-(s1-1)*s1/2;//数学公式算一下即可
    ll b=(1+s2)*s2/2;
    printf("%lld\n",a-b);
}

E. Data Structures Fan

题意:有n个数,同时给长度为n的 01串,有q次询问,其中有两种操作"1 L R"和"2 g ( g=0 || g=1 )"分别表示把区间[L,R]中的01反转,0变1,1变0,第二种表示询问01串中等于g的所有位置 i 对应的ai异或,输出这个值。

解析:翻转区间[l,r],对于总的s[i]=0的异或总和ans0刚好就是 ans0^=(a[l]^a[l+1]^...^a[r]),ans1同理,因此维护一下异或前缀和即可。

cpp 复制代码
int a[N],b[N];
char s[N];
void solve()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    scanf("%s",s+1);
    for(int i=1;i<=n;i++) b[i]=b[i-1]^a[i];
    int ans0=0,ans1=0;
    for(int i=1;i<=n;i++)
    {
        if(s[i]=='0') ans0^=a[i];
        else ans1^=a[i];
    }
    int q;
    scanf("%d",&q);
    while(q--)
    {
        int op;
        scanf("%d",&op);
        if(op==1)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            ans0^=b[r]^b[l-1];
            ans1^=b[r]^b[l-1];
        }else
        {
            int g;
            scanf("%d",&g);
            if(g==0) printf("%d ",ans0);
            else printf("%d ",ans1);
        }
    }
    printf("\n");
}

F. Selling a Menagerie

题意:有n个动物,每个动物有价值wi,每个动物有一个前置点,如果售卖该动物时,他的前置点还没有被卖,那么你会获得2*wi,否则获得wi,要求你输出一个售卖动物的顺序,是否获得价值最大。

解析:假设关系是一条链,那么肯定是从最后一个点(入度为0)开始卖,直到第一个点,这样价值肯定是最大的,但题中其实会出现有环的情况,但其实不复杂,我们只要使得损失最小即可,我们可以选择环中价值最低的那一个最后卖即可,非环的跑一次拓扑即可,怎么判断该点是否在环中呢,其实跑完拓扑,没有遍历到的点就是在环中。

cpp 复制代码
typedef long long ll;
vector<int> v[N],ans;
ll w[N];//每个点的价值
int n,d[N],ne[N];//分别记录入度和当前点的前置点
bool vis[N];//表示该点是否访问过
void topsort()
{
    queue<int> q;
    for(int i=1;i<=n;i++)
    {
        if(!d[i])
        {
            q.push(i);
            ans.push_back(i);
            vis[i]=true;
        }
    }
    while(q.size())
    {
        int x=q.front();
        q.pop();
        for(int i=0;i<v[x].size();i++)
        {
            int j=v[x][i];
            if(--d[j]==0)
            {
                ans.push_back(j);
                vis[j]=true;
                q.push(j);
            }
        }
    }
}
void solve()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x),v[i].push_back(x);
        ne[i]=x;//下一个节点
        d[x]++;
    }
    for(int i=1;i<=n;i++) scanf("%lld",&w[i]);
    topsort();
    for(int i=1;i<=n;i++)
    {
        if(!vis[i])//还没访问过,表示在环中
        {
            int root=i,pos=i;
            ll mi=w[root];
            while(1)
            {
                int k=ne[pos];//下一个节点
                if(k==root) break;//如果回到了自身退出
                if(w[k]<mi)
                {
                    mi=w[k];
                    root=k;//记录环中最小值
                }
                pos=k;
            }
            pos=root;
            while(1)//从root开始跑一次环,记录答案
            {
                int k=ne[pos];
                if(k==root) break;
                ans.push_back(k);
                vis[k]=true;
                pos=k;
            }
            ans.push_back(root);//最后把root放进答案
            vis[root]=true;
        }
    }
    for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
    printf("\n");
    for(int i=1;i<=n;i++) d[i]=0,v[i].clear(),vis[i]=false;//多组初始化
    ans.clear();
}

G. Replace With Product

题意:给定n个数,你可以仅操作一次,使得[L,R]这一段替换区间乘积,让你输出L,R使得最后序列总和最大。

解析:正常来贪,肯定选择第一个非1到最后一个非1这个区间,但有些情况并不满足,但是如果区间乘积>=1e9之后,肯定就是选择上述区间,对于总的乘积<1e9的情况,可以发现>1的个数肯定 很少,直接暴力枚举每对位置即可,当然可以用前缀和以及前缀积优化,对于每种跟答案取max即可。

cpp 复制代码
typedef long long ll;
ll a[N],sum[N],mul[N];//分别表示原数组,前缀和,前缀积
void solve()
{
    int n,l=-1,r=-1;//表示答案区间
    ll s=1;
    vector<int> v;
    scanf("%d",&n);
    mul[0]=1;//初始化
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    for(int i=1;i<=n;i++)
    {
        if(a[i]!=1)
        {
            v.push_back(i);
            if(l==-1) l=i;//第一个非1数字
            r=i;//最后一个非1数字
        }
        sum[i]=sum[i-1]+a[i];
        mul[i]=mul[i-1]*a[i];
    }
    for(int i=1;i<=n;i++)
    {
        s*=a[i];
        if(s>=1e9)
        {
            printf("%d %d\n",l,r);
            return;
        }
    }
    ll mx=0;
    for(int i=0;i<v.size();i++)
    {
        for(int j=i;j<v.size();j++)
        {
            int x=v[i],y=v[j];
            if(sum[x-1]+mul[y]/mul[x-1]+sum[n]-sum[y]>mx)
            {
                mx=sum[x-1]+mul[y]/mul[x-1]+sum[n]-sum[y];
                l=x,r=y;
            }
        }
    }
    if(l==-1) l=1,r=1;
    printf("%d %d\n",l,r);
}
相关推荐
爱吃生蚝的于勒1 小时前
C语言内存函数
c语言·开发语言·数据结构·c++·学习·算法
小白学大数据3 小时前
Python爬虫开发中的分析与方案制定
开发语言·c++·爬虫·python
失落的香蕉4 小时前
C语言串讲-2之指针和结构体
java·c语言·开发语言
versatile_zpc6 小时前
C++初阶:类和对象(上)
开发语言·c++
小鱼仙官6 小时前
MFC IDC_STATIC控件嵌入一个DIALOG界面
c++·mfc
神仙别闹6 小时前
基本MFC类框架的俄罗斯方块游戏
c++·游戏·mfc
ChoSeitaku7 小时前
链表循环及差集相关算法题|判断循环双链表是否对称|两循环单链表合并成循环链表|使双向循环链表有序|单循环链表改双向循环链表|两链表的差集(C)
c语言·算法·链表
娅娅梨7 小时前
C++ 错题本--not found for architecture x86_64 问题
开发语言·c++
DdddJMs__1357 小时前
C语言 | Leetcode C语言题解之第557题反转字符串中的单词III
c语言·leetcode·题解
兵哥工控7 小时前
MFC工控项目实例二十九主对话框调用子对话框设定参数值
c++·mfc