Codeforces Round #618(部分)

Anu Has a Function

题意:定义了一种运算f(x,y)=(x|y)−y,给你一个数组要求重新排列,使得依次做这种运算后得到的答案最大

思路:观察运算中又位运算,手推几个运算后发现这种运算结束后y的各个为都是0,所以推算出f(x,y)=x-(x&y)。因此当数组依次运算之后,结果就是第一位的数字各个位减去后面数字的各个位,所以答案最大时需要满足数组的第一个数各位减去后面的数后最大,也就是第一个数字拥有单独的最大位,后面的数字顺序无所谓。

代码:

#include <bits/stdc++.h>
#define x first
#define y second
#define mid (l + r >> 1)
#define lo (o << 1)
#define ro (lo | 1)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const ll mod = 998244353;
struct tri{int x,y,z;};

int sum[35],arr[maxn];
 
int main()
{
    // freopen("in.txt","r",stdin);
    int n;scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%d",arr+i);
        int tmp=arr[i];
        for(int j=0;tmp;j++)
        {
            sum[j]+=tmp&1;
            tmp>>=1;
        }
    }
    int id=-1;//单独位的最高位
    for(int i=0;i<35;i++)
        if(sum[i]==1)id=i;
    if(~id)for(int i=0;i<n;i++)
        if(arr[i]&1<<id)swap(arr[0],arr[i]);
    for(int i=0;i<n;i++)
        printf("%d ",arr[i]);
    return 0;
}

Aerodynamic

题意:给一个n边形,保证n个点是按照逆时针给出,问这个n边形绕着原点平移一圈所形成的形状和原图形是否相同。

思路:画图模拟一下猜想出结论,只有这个图形是中心对称图形时就yes,否则no。判断中心对称的方式就是判断第i条向量和第i+n/2条向量满足\overrightarrow{i}+\overrightarrow{i+n/2}==0

代码:

#include <bits/stdc++.h>
#define x first
#define y second
#define mid (l + r >> 1)
#define lo (o << 1)
#define ro (lo | 1)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const ll mod = 998244353;
struct tri{int x,y,z;};
 
pii arr[maxn];
int n;
pii operator+(pii a,pii b)
{
    return pii({a.x+b.x,a.y+b.y});
}
 
bool solve()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)scanf("%d%d",&arr[i].x,&arr[i].y);
    arr[n]=arr[0];
    if(n&1)return 0;
    for(int i=0;i<n/2;i++)
    {
        if(arr[i]+arr[i+n/2]!=arr[i+1]+arr[i+n/2+1])return 0;
    }
    return 1;
}
 
int main()
{
    // freopen("in.txt","r",stdin);
    if(solve())puts("yes");
    else puts("no");
    return 0;
}

Water Balance

题意:给n个数,可以将任意区间内的数平均,让你求出操作过后可以得到的最小字典序。

思路:看上去很像线段树,但实际上只用贪心就可以解决。题中的重点就是字典序最小,所q以就需要将前面的值降到尽可能得小,就可以想到一种纯贪心的做法:容易推出最终答案一定是一个升序序列,因为一旦相邻的两个数是降序就一定需要将这两个数合并,所以一种得到升序的做法就是从前往后依次判断相邻的两个数大小关系,当前者比后者大时,就合并这两堆,而当合并之后如果又比前面的前面那一堆小,就再合并前面的一堆和更前面的一堆,直到每一堆都是升序无法再合并。

这里用一个pair<double,int>存储每一堆的信息,double是平均值,int是数量,最后依次输出就可以了。

代码:

#include <bits/stdc++.h>
#define x first
#define y second
#define mid (l + r >> 1)
#define lo (o << 1)
#define ro (lo | 1)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<double, int> pdi;
typedef vector<int> vi;
const int maxn = 1e6 + 10;
const int inf = 0x3f3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const ll mod = 998244353;
struct tri{int x,y,z;};
 
pdi ans[maxn];
int tot=0,n;
 
int main()
{
    // freopen("in.txt","r",stdin);
    ans[0]={0,0};
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        int a;scanf("%d",&a);
        ans[++tot]={a,1};
        while(ans[tot].x<=ans[tot-1].x)
        {
            ans[tot-1].x=ans[tot-1].x*ans[tot-1].y+ans[tot].x*ans[tot].y;
            ans[tot-1].y+=ans[tot].y;
            ans[tot-1].x/=ans[tot-1].y;
            tot--;
        }
    }
    for(int i=1;i<=tot;i++)
        for(int j=0;j<ans[i].y;j++)
            printf("%.15lf\n",ans[i].x);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43700916/article/details/104244982