Educational Codeforces Round 99 (Rated for Div. 2)

58 篇文章 0 订阅
35 篇文章 1 订阅

A. Strange Functions

题意:定义f()函数为把放进去的数倒置,并去掉前导零。 g ( x ) = x f ( f ( x ) ) g(x)=\frac{x}{f(f(x))} g(x)=f(f(x))x,给定n。在所有 1<= x <= n中,能使得g(x)取得几个不同的值。

思路:f(x)套了两层,先倒置去掉了前导零,又倒置去掉了前导零。其实就是倒回来了。然后用x去除它。假设x后面没有0。那么g(x)就是1。如果有一个0,那就是10。以此类推。所以答案就是n的位数。想必找规律也能看出来。

AC代码:

#include <iostream>
#include <bits/stdc++.h>
#define int long long
#define mk make_pair
#define gcd __gcd
using namespace std;
const double eps = 1e-10;
const int mod = 1e9+7;
const int N = 3e5+7;
int n,m,k,t = 1,cas = 1;
int a[N],b[N];
int ans[N];
 
signed main(){
    cin>>t;
    while(t--){
        string s;
        cin>>s;
        cout<<s.size()<<endl;
    }
}

B. Jumps

题意:初始在0点。要跳到x点(x > 0)。在第i次跳跃中。要么跳到 y+i的位置,要么跳到y-1的位置。求到x,最少跳多少步。

思路:先考虑最简单的情况。就是先一直往右跳。跳过头了,再慢慢跳回来。这样就可以求出。至少要往右跳x次。然后可以发现。如果跳过头了,是比较亏的。因为可能要花很多步再跳回来。那怎么避免跳过头呢。就是提前往回跳。从而避免一次往右跳。这样就相当于少往右走了i-1步。枚举这个i。看看有没有可行解就行了。

AC代码:

#include <iostream>
#include <bits/stdc++.h>
#define int long long
#define mk make_pair
#define gcd __gcd
using namespace std;
const double eps = 1e-10;
const int mod = 1e9+7;
const int N = 3e5+7;
int n,m,k,t = 1,cas = 1;
int a[N],b[N];
int ans[N];
int sel = 0;
signed main(){
    cin>>t;
    while(t--){
        cin>>n;
        int now = 0;
        int res = 0;
        int last = 0;
        for(int i = 1 ; now < n ; i ++){
            now += i;
            res ++;
            last = i;
        }
        res += now-n;
        int tmp = now-n;
        for(int i = 1 ; i <= last ; i ++){
            if(now-i-1 == n){
                res = min(res,res-tmp);
            }
        }
        cout<<res<<endl;
    }
}

C. Ping-pong

题意:两个人打乒乓球。分别有x,y次击球机会。发球也算。有击球机会100%能打回去。 没机会100%打不回去。但是可以选择不打。保留次数。在保证能让自己多赢对手少赢的情况下。求每个人最多可以赢多少局。

思路:很容易想到。先手发球时很亏的。因为要赢的话,得浪费两次机会。而后手可以用一次机会获胜。如果对手机会没了。那直接发球就赢了。所以贪心策略就出来了。 如果对手还有机会,并且它发球。那我不接。让他赢。如果他是最后一次机会了。那我打回去。 我就赢一局了。剩下的我随便打。对面没机会了我全赢。所以后手y次机会就能赢y次。先手赢x-1次。

AC代码:

#include <iostream>
#include <bits/stdc++.h>
#define int long long
#define mk make_pair
#define gcd __gcd
using namespace std;
const double eps = 1e-10;
const int mod = 1e9+7;
const int N = 3e5+7;
int n,m,k,t = 1,cas = 1;
int a[N],b[N];
int ans[N];
int sel = 0;
map<int,int> mp;
struct node{
    int x,w;
    node(int a,int b):x(a),w(b){}
};
queue<node> que;
 
signed main(){
    cin>>t;
    while(t--){
        int x,y;
        cin>>x>>y;
        int res1 = 0;
        int res2 = 0;
        res1 = x-1;
        res2 = y;
        cout<<res1<<" "<<res2<<endl;
    }

D. Sequence and Swaps

题意:给定一个数组和一个x。然后每次可以选择一个比x大的数,swap(a[i],x),然后重复这个操作。直到数组有序。

思路:首先,这样连续的交换,一定是发生在一个递增子序列上的。因为x在不断的变大。那么这个子序列的起点就很重要了。枚举一个起点。然后碰到比x大的就交换。因为如果碰到比x大的而不交换的话。必须保证后面都是有序的,如果后面还有不是有序的。那么这次不交换。之后就更不能换了。肯定时无序的。

AC代码:

#include <iostream>
#include <bits/stdc++.h>
#define int long long
#define mk make_pair
#define gcd __gcd
using namespace std;
const double eps = 1e-10;
const int mod = 1e9+7;
const int N = 3e5+7;
int n,m,k,t = 1,cas = 1;
int a[N],b[N];
int ans[N];
bool check(int n){
    for(int i = 1 ; i <= n ; i ++){
        if(b[i] < b[i-1]) return false;
    }
    return true;
}
int cal(int pos){
    int now = b[pos];
    b[pos] = m;
    int cnt = 1;
    for(int i = pos ; i <= n ; i ++){
        if(check(n)) return cnt;
        if(b[i] > now){
            swap(b[i],now);
            cnt ++;
        }
    }
    if(!check(n)) return -1;
    return cnt;
}

signed main(){
    cin>>t;
    while(t--){
        cin>>n>>m;
        for(int i = 1 ; i <= n ; i ++) cin>>a[i],b[i] = a[i];
        a[0] = 0; a[n+1] = 1e9;
        int res = 1e18;
        if(check(n)) res = 0;
        for(int i = 1 ; i <= n ; i ++){
            if(a[i] <= m) continue;
            for(int j = 1 ; j <= n ; j ++)
                b[j] = a[j];
            int tmp = cal(i);
            if(tmp != -1){
                res = min(res,tmp);
            }
        }
        if(res < 1e18){
            cout<<res<<endl;
        }else{
            cout<<-1<<endl;
        }
    }
}
/**
**/

E. Four Points

题意:给四个点。移动他们,使得形成一个正方形。 求最小移动步数。

思路参考:https://www.cnblogs.com/qieqiemin/p/14069636.html

思路: x和y可以分开考虑。 首先枚举每个点作为四个点的任意一个点。也就是枚举所有排列。然后再进行计算。单独考虑x。设左下,右下,左上,右上,分别为 p0,p1,p2,p3。然后对于 p0-p2,可以求出一个x的范围 x1-x2。就是min(p0.x,p2.x) - max(p0.x,p2.x) 。同理对于 p1-p3 一样求。然后就会得出两个区间。 如果左边小于右边。那就让他们移动到各自的中点去就行了。这样移动距离是最小的。如果右边 小于左边。那就全部移动到min(p0.x,p2.x)就好了。边长为0也是合法的。对于y轴。是一样考虑的。这时候。得到了一个 水平的边长范围。和一个竖直的边长范围。如果 横着和竖着有交集。那就直接是 costx+costy。就是总的cost。如果没有交集。那必然需要两个点做出让步。移动到边长相等的地方去。这就加上额外的cost就行了。

AC代码:

#include <bits/stdc++.h>
#define int long long
#define mk make_pair
using namespace std;
const int N = 1e6+7;
const int mod = 1e9+7;
int t = 1,n,m,k;
struct node{
    int x,y;
}p[N];
int sum[N];

set<pair<int,int> > st;

signed main(){
    cin>>t;
    while(t-- ){
        int b[] = {0,1,2,3};
        for(int i = 0 ; i < 4 ; i ++){
            cin>>p[i].x>>p[i].y;
        }
        int res = 1e18;
        do{
            int x1 = min(p[b[0]].x,p[b[2]].x);
            int x2 = max(p[b[0]].x,p[b[2]].x);
            int x3 = min(p[b[1]].x,p[b[3]].x);
            int x4 = max(p[b[1]].x,p[b[3]].x);

            int y1 = min(p[b[0]].y,p[b[1]].y);
            int y2 = max(p[b[0]].y,p[b[1]].y);
            int y3 = min(p[b[2]].y,p[b[3]].y);
            int y4 = max(p[b[2]].y,p[b[3]].y);

            int costx,costy;
            int x_l,x_r,y_l,y_r;

            if (x4 < x1) {
                x_l = x_r = 0;
                costx = x2 - x3 + x1 - x4;
            } else {
                x_l = max(x3 - x2, 0ll);
                x_r = x4 - x1;
                costx = x2 - x1 + x4 - x3;
            }

            if (y4 < y1) {
                y_l = y_r = 0;
                costy = y2 - y3 + y1 - y4;
            } else {
                y_l = max(y3 - y2, 0ll);
                y_r = y4 - y1;
                costy = y2 - y1 + y4 - y3;
            }

            int cost = costx + costy;
            if (y_l > x_r) {
                cost += (y_l - x_r) << 1;
            } else if (x_l > y_r) {
                cost += (x_l - y_r) << 1;
            }
            res = min(res, cost);
        }while(next_permutation(b,b+4));
        cout<<res<<endl;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值