Codeforces Round #702 (Div. 3) A-G

71 篇文章 0 订阅

A. Dense Array
给你 n n n 个数的数组,定义数组有效为任意两个相邻的数 m a x ( a r r [ i ] , a r r [ i − 1 ] ) / m i n ( a r r [ i ] , a r r [ i − 1 ] ) < = 2 max(arr[i],arr[i-1])/min(arr[i],arr[i-1]) <= 2 max(arr[i],arr[i1])/min(arr[i],arr[i1])<=2 那么按照题意check 补数即可,注意要从小的去不断的乘2去构造,大的 / 2 会有精度损失

#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#include<stack>
#include<string>
#include<iostream>
#include<set>
#include<algorithm>
using namespace std;
 
#define ll long long
#define dbg(x) cout << #x << " = " << (x) << endl;
#define dbg2(x,y) cout << #x << " = " << (x) << " " << #y << " = " << (y) << endl;
const int MAX_N = 55;
ll arr[MAX_N];
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i = 1;i<=n;++i)
        {
            scanf("%lld",&arr[i]);
        }
        arr[0] = arr[1];
        arr[n+1] = arr[n];
        ll ans = 0;
        for(int i = 1;i<=n;++i)
        {
            ll tmp = arr[i];
            while(tmp*2<arr[i-1])
            {
                tmp*=2;
                ans++;
            }
            tmp = arr[i];
            while(tmp*2<arr[i+1])
            {
                tmp*=2;
                ans++;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

B. Balanced Remainders
给你 n n n 个数, n n n 3 3 3 的倍数,问你每次可以加一个数加一,问你最少操作使得 n n n 个数每个数 % 3 3 3 所得的数总和分别为 n / 3 n/3 n/3 ,这题卡了一下 我们发现做法是将 % 3 = 0 3 = 0 3=0 的数加一变为 % 3 = 1 3 = 1 3=1 , 后来觉得跑两次 最终情况一定在这两次之间 得出答案 我们发现只要大小 > n / 3 > n/3 >n/3 则需要往下一个数组进,缺少则需要上个数组来 我们跑两次正好模拟了所有情况

#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#include<stack>
#include<string>
#include<iostream>
#include<set>
#include<algorithm>
using namespace std;
 
#define ll long long
#define dbg(x) cout << #x << " = " << (x) << endl;
#define dbg2(x,y) cout << #x << " = " << (x) << " " << #y << " = " << (y) << endl;
const int MAX_N = 30025;
int arr[MAX_N];
int cnt[5],brr[5];
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        cnt[0] = cnt[1] = cnt[2] = 0;
        for(int i = 1;i<=n;++i) scanf("%d",&arr[i]),arr[i] = (arr[i]%3),cnt[arr[i]]++;
        int ans = 0;
        for(int i = 0;i<3;++i)
        {
            int tmp =max(cnt[i]-n/3,0);
            cnt[i] -= tmp;
            if(i!=2) cnt[i+1]+=tmp;
            else cnt[0] += tmp;
            ans+=tmp;
        }
        for(int i = 0;i<3;++i)
        {
            int tmp =max(cnt[i]-n/3,0);
            cnt[i] -= tmp;
            if(i!=2) cnt[i+1]+=tmp;
            else cnt[0] += tmp;
            ans+=tmp;
        }
        printf("%d\n",ans);
    }
    return 0;
}

C. Sum of Cubes
判断一个数是否是两个立方的和 数小于等于 1 e 12 1e12 1e12 那么我们遍历 1 e 4 1e4 1e4 即可,用 m p mp mp 判断是否存在

#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#include<stack>
#include<string>
#include<iostream>
#include<set>
#include<algorithm>
using namespace std;
 
#define ll long long
#define dbg(x) cout << #x << " = " << (x) << endl;
#define dbg2(x,y) cout << #x << " = " << (x) << " " << #y << " = " << (y) << endl;
const int MAX_N = 10005;
 
map<ll,int> mp;
 
void init()
{
    for(ll i = 1;i<=10000;++i)
    {
        if(i*i*i>1e12) break;
        if(mp.find(i*i*i)==mp.end()) mp[i*i*i] = 0;
        else mp[i*i*i]++;
    }
}
int main()
{
    init();
    int t;
    ll n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld",&n);
        bool flag = false;
        for(ll i = 1;i<=10000;++i)
        {
            if(i*i*i>n) break;
            if(mp.find(n-i*i*i)!=mp.end())
            {
                flag = true;
                break;
            }
        }
        if(flag) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

D. Permutation Transformation
应该是前序遍历 分治即可

#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#include<stack>
#include<string>
#include<iostream>
#include<set>
#include<algorithm>
using namespace std;
 
#define ll long long
#define dbg(x) cout << #x << " = " << (x) << endl;
#define dbg2(x,y) cout << #x << " = " << (x) << " " << #y << " = " << (y) << endl;
const int MAX_N = 105;
 
int arr[MAX_N],ans[MAX_N];
void dfs(int l,int r,int dep)
{
    if(l>r) return;
    if(l==r) {
        ans[l] = dep;
        return;
    }
    int maxx = 0,xb;
    for(int i = l;i<=r;++i) if(arr[i]>maxx) maxx = arr[i],xb = i;
    ans[xb] = dep;
    dfs(l,xb-1,dep+1);
    dfs(xb+1,r,dep+1);
}
 
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        for(int i = 1;i<=n;++i) scanf("%d",&arr[i]);
        dfs(1,n,0);
        for(int i = 1;i<=n;++i) i==n?printf("%d\n",ans[i]):printf("%d ",ans[i]);
    }
    return 0;
}

E. Accidental Victory
给你 n n n 个人 每次选出两个值非空的人 只要一人值大于等于另一个人 则有机会吞下另一个人的值(相等时随机)
问你有可能赢的人的编号 我们维护前缀和,然后值一样的人前缀和应该相同,所以需要倒着更新一次
只要判断前缀和是否能大于等于下个人的下标 则可以判断这人能不能吃下下一个人
我们认为能吃下最大的人的就能赢 所以按逻辑维护一次即可

#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#include<stack>
#include<string>
#include<iostream>
#include<set>
#include<algorithm>
using namespace std;
 
#define ll long long
#define dbg(x) cout << #x << " = " << (x) << endl;
#define dbg2(x,y) cout << #x << " = " << (x) << " " << #y << " = " << (y) << endl;
const int MAX_N = 200025;
ll sum[MAX_N];
struct node
{
    int x,id;
    bool operator < (const node &other) const
    {
        return x < other.x;
    }
}arr[MAX_N];
int uniq[MAX_N];
 
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        set<int> st;
        int n,len = 0;
        scanf("%d",&n);
        for(int i = 1;i<=n;++i) scanf("%d",&arr[i].x),arr[i].id = i;
        sort(arr+1,arr+1+n);
        for(int i = 1;i<=n;++i)
        {
            if(i==1||arr[i].x!=arr[i-1].x) uniq[++len] = i;
        }
        uniq[len+1] = uniq[len];
        for(int i = 1;i<=n;++i) sum[i] = sum[i-1] + arr[i].x;
        for(int i = n;i>=2;--i)
        {
            if(arr[i-1].x==arr[i].x) sum[i-1] = sum[i];
        }
        int xb = 1;
        arr[n+1].x = 0;
        for(int i = 1;i<=n;++i)
        {
            while(xb+1<=len+1&&arr[uniq[xb]].x<=arr[i].x) xb++;
            if(sum[i]>=arr[uniq[xb]].x) st.insert(arr[i].id);
            else st.clear();
        }
        printf("%d\n",st.size());
        for(set<int>::iterator it = st.begin();it!=st.end();++it)
        {
            printf("%d ",*it);
        }
        printf("\n");
    }
    return 0;
}

F. Equalize the Array
其实问题本质是 最大矩形简易版 高度按顺序排好
证明:数为矩形分布的时候则满足条件,那么总面积不变,最大矩形最大则去掉的数最少

#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#include<stack>
#include<string>
#include<iostream>
#include<set>
#include<algorithm>
using namespace std;
 
#define ll long long
#define dbg(x) cout << #x << " = " << (x) << endl;
#define dbg2(x,y) cout << #x << " = " << (x) << " " << #y << " = " << (y) << endl;
const int MAX_N = 200025;
int arr[MAX_N],brr[MAX_N];
map<int,int> mp;
multiset<int> st;
 
int main()
{
    int n,t;
    scanf("%d",&t);
    while(t--)
    {
        ll ans = 0x3f3f3f3f3f3f3f;
        ll sum = 0;
        ll cnt = 0;
        st.clear();
        mp.clear();
        scanf("%d",&n);
        for(int i = 1;i<=n;++i)
        {
            scanf("%d",&arr[i]);
            brr[i] = arr[i];
            if(mp.find(arr[i])==mp.end()) mp[arr[i]] = 1;
            else mp[arr[i]]++;
        }
        sort(brr+1,brr+1+n);
        int sz = unique(brr+1,brr+1+n) - (brr+1);
        for(int i = 1;i<=sz;++i)
        {
            st.insert(mp[brr[i]]);
            sum+=mp[brr[i]];
        }
        for(multiset<int>::iterator it= st.begin();it!=st.end();++it)
        {
            ans = min(ans,sum-1ll*(sz-cnt)*(*it));
            cnt++;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

G. Old Floppy Drive
我们发现一个性质是说 如果前缀和大于等于查询的 x x x 那么扫一次肯定能得到答案,否则我们需要看下第 n n n 个前缀和是否大于 0 0 0 , 大于才有贡献 然后我们就能把问题简化为扫一次(多次的用除法得到),我们想得到值大于等于当前 x x x 的最左边的数,可以围绕一个 a n s ans ans 数组 意义是达到此值的最左下标,因为你可能第 3 3 3 的前缀和到了 2 2 2 ,第 4 4 4 的前缀和到了 1 1 1 ,你想要找 1 1 1 直接二分会找到下标 4 4 4 ,其实我们发现下标 3 3 3 才是想要的答案 所以 a n s ans ans 数组能满足这个需求 收货就是 a n s ans ans 数组思想挺巧妙的

#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#include<stack>
#include<string>
#include<iostream>
#include<set>
#include<algorithm>
using namespace std;
 
#define ll long long
#define dbg(x) cout << #x << " = " << (x) << endl;
#define dbg2(x,y) cout << #x << " = " << (x) << " " << #y << " = " << (y) << endl;
#define dbg3(x,y,z) cout << #x << " = " << (x) << " " << #y << " = " << (y) << " " << #z << " = " << (z) << endl;
const int MAX_N = 200025;
int arr[MAX_N],ans[MAX_N];
ll sum[MAX_N];
struct node
{
    ll x;
    int id;
    bool operator < (const node &other) const
    {
        return x < other.x;
        if(x==other.x) return id > other.id;
    }
}brr[MAX_N];
 
int main()
{
    int t,n,m;
    ll x;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i = 1;i<=n;++i)
        {
            scanf("%d",&arr[i]);
        }
        for(int i = 1;i<=n;++i)
        {
            sum[i] = sum[i-1]+arr[i];
            brr[i].x = sum[i];
            brr[i].id = i;
        }
        sort(brr+1,brr+1+n);
        ans[n+1] = MAX_N;
        for(int i = n;i>=1;--i)
        {
            ans[i] = min(brr[i].id,ans[i+1]);
        }
        while(m--)
        {
            scanf("%lld",&x);
            if((sum[n]<=0&&brr[n].x<x))
            {
                printf("-1 ");
                continue;
            }
            if(x<=brr[n].x)
            {
                int l = 1,r = n;
                while(l<=r)
                {
                    int mid = l+r>>1;
                    if(brr[mid].x>=x) r = mid - 1;
                    else l = mid + 1;
                }
                printf("%d ",ans[l]-1);
            }
            else
            {
                ll tmp = (x-brr[n].x);
                ll cnt = (tmp-1)/sum[n] + 1;
                x-=cnt*sum[n];
                int l = 1,r = n;
                while(l<=r)
                {
                    int mid = l+r>>1;
                    if(brr[mid].x>=x) r = mid - 1;
                    else l = mid + 1;
                }
                printf("%lld ",ans[l]-1+(cnt*n));
            }
        }
        printf("\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值