2022.4.10

AtCoder Regular Contest 138

A - Larger Score

搞个结构体,存储每个点的值和位置,从大到小排序,当值相等时位置小的在前面。利用pos和ans找到当前大于k且id最小的点,和小于k的点,不断更新最小值。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=4e5+10,INF=1e9;
struct node
{
    int val, id;
} a[N];
bool cmp(node a,node b)
{
    if(a.val==b.val)
    {
        return a.id < b.id;
    }
    return a.val > b.val;
}
int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    int n, k;
    cin >> n >> k;
    for (int i = 1; i <= n;i++)
    {
        int x;
        cin >> x;
        a[i] = {x, i};
    }
    sort(a + 1, a + 1 + n,cmp);
    int pos = 1e9, ans = 1e9;
    for (int i = 1; i <= n;i++)
    {
        if(a[i].id>k)
        {
            pos = min(pos, a[i].id);
        }
        else
        {
            ans = min(ans, pos-a[i].id);
        }
    }
    if(ans>n)
        cout << -1;
    else
        cout << ans;
        return 0;
}

B - 01 Generation

反向操作一遍看能不能把序列变成空序列。一种操作是在开头加个0并把后面的数都翻转,第二种操作是在末尾加0.首先知道不论哪种操作1都肯定不会在第一位,所以反向操作的时候如果开头为1就可以直接判断no了,否则不断把队尾的0删掉,然后队头删掉再把后面的反转,直到i>j。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=2e5+10,INF=1e9;
int a[N];
int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    int n;
    cin >> n;
    for (int i = 1; i <= n;i++)
        cin >> a[i];
    if(a[1]==1)
    {
        cout << "No" << '\n';
    }
    else
    {
        int f = 1,ans=0;
        for (int i = 1, j = n; i <= j;)
        {
            if(!(a[i]^f))
            {
                ans=1;
                break;
            }
            if(a[j]^f)
            {
                j--;
            }
            else
            {
                i++;
                f ^= 1;
            }
        }
        if(!ans)
            cout << "Yes";
        else
            cout << "No";
    }
        return 0;
}

Educational Codeforces Round 126 (Rated for Div. 2)

A. Array Balancing

如果交换完的绝对值比交换前的小的话就交换。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e9;
int a[N], b[N];
int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin >> n;
        for (int i = 1; i <= n;i++)
            cin >> a[i];
        for (int i = 1; i <= n;i++)
            cin >> b[i];
        for (int i = 1; i <n;i++)
        {
            if(abs(a[i]-a[i+1])+abs(b[i]-b[i+1])>abs(b[i]-a[i+1])+abs(a[i]-b[i+1]))
                swap(a[i+1], b[i+1]);
        }
        ll sum = 0;
        for (int i = 1;i<n;i++)
        {
            sum += abs(a[i] - a[i + 1]);
            sum += abs(b[i] - b[i + 1]);
        }
        cout << sum << '\n';
    }

    return 0;
}

B. Getting Zero

32768是2的15次方,需要把一个数变成2^15次方x,取模即为0。对于这个数我们可以选择加1或者2,于是可以枚举+1和*2的操作,取得最小值。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e9,mod=32768;
int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    int n;
    cin >> n;
    for (int i = 1; i <= n;i++)
    {
        int x,ans=INF;
        cin >> x;
        for (int j = 0; j <= 15;j++)
        {
            int xx = (x + j) % mod;
            int cnt = j;
            while(xx)
            {
                xx = xx * 2 % mod;
                cnt++;
            }
            ans = min(ans, cnt);
        }
        cout << ans << ' ';
    }
        return 0;
}

C. Water the Trees

然你求吧所有树都变成同样高度的最小次数,奇数天高度加一,偶数天高度加二,未必长到和最高的树一样的高度就是花费最小的,如:1 1 1 1 2。但所有树为max+1时花费最小。但不可能为max+2,因为这样可以用1来代替2。可以利用二分来写,满足时间的单调性,二分天数mid,在mid天里有(mid-1)/2天可以+1,有mid-cnt1天可以加2。基于贪心的策略我们应该先把+2的次数用完剩下的考虑用+1来补充,因此对于mid我们计算出所有树减去+2后需要的+1的次数,如果+1次数充足的满足,r=mid,否则+1次数不够不满足,为l=mid+1.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=3e5+10,INF=1e9;
int a[N];
int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--)
    {
        int n,mmax=-1;
        cin>>n;
        for (int i = 1; i <= n;i++)
        {
            cin >> a[i];
            mmax = max(mmax,a[i]);
        }
        ll ans = 1e18;
        for (ll i = mmax; i <= mmax + 1;i++)
        {
            ll l = 0, r = 1e18;
            while(l<r)
            {
                ll mid = l + r >> 1;
                ll cnt1 = (mid + 1) / 2, cnt2 = mid - cnt1;
                ll need1 = 0;
                for (int j = 1; j <= n;j++)
                {

                    ll now = (i - a[j]) / 2;
                    if((i-a[j])%2==1)
                    {
                        need1++;
                    }
                    if(cnt2>=now)
                    {
                        cnt2 -= now;
                    }
                    else
                    {
                        now -= cnt2;
                        cnt2 = 0;
                        need1 += now * 2;
                    }
                }
                if(need1<=cnt1)
                {
                    r = mid;
                }
                else
                    l = mid + 1;
            }
            ans = min(ans, l);
        }
        cout << ans << '\n';
    }

    return 0;
}

SZTU Monthly 2022 Mar.

D (1322) : 切木棍

可知最后一定是化为平均值,二分操作次数,注意是(a[i]-1)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=2e5+10,INF=1e8;
int a[N],n, k;
bool check(int mid)
{
    int ans = 0;
    for (int i = 1; i <= n;i++)
    {
        ans += (a[i]-1) / mid ;
    }
    return ans <= k;
}
int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    cin >> n >> k;
    int mmax = -1;
    for (int i = 1; i <= n;i++)
    {
        cin >> a[i];
        mmax = max(a[i], mmax);
    }
    if(k==0)
    {
        cout << mmax;
    }
    else
    {
        int l = 1, r = 1e9+1;
        while(l<r)
        {
            int mid = l + r  >> 1;
            if(check(mid))
                r=mid;
            else
                l = mid + 1;
        }
        cout << r << '\n';
    }
    return 0;
}

J (1328) : 吃奶酪

转态压缩当前的状态注意从1开始选取当前最小的点开始搜索,在任意的时刻,dp[i][j]=min(dp[i][j],dp[i^(1<<j)][k]+w[k][j]),异或是因为当前转态和上一个状态只能有一个点在j,然后对于每一位是1的位k,我们可以由k转移到j,于是记录一下转移的最小值。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=17,INF=1e9;
double a[N], b[N],dis[1<<N][N];
double dist(double x1,double y1,double x2,double y2)
{
    return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    int n;
    cin>>n;
    for (int i = 1; i <= n;i++)
    {
        cin >> a[i] >> b[i];
    }
    for (int i = 0; i <= (1 << (n+1)) ;i++)
    {
        for (int j = 0; j <= n;j++)
        {
            dis[i][j] = 1e8*1.0;
        }
    }
    dis[1][0] = 0;
    for (int i = 1; i < 1 << (n+1) ;i++)
    {
        for (int j = 1; j <= n;j++)
        {
            if((i>>j)&1)
            {
                for (int k = 0; k <= n;k++)
                {
                    if(i-(1<<j)>>k&1)
                    {
                        double distt = dist(a[j], b[j], a[k], b[k]);
                        dis[i][j] = min(dis[i][j], dis[i-(1<<j)][k] + distt);
                    }
                }
            }
        }
    }
    double ans = 1e8 * 1.0;
    for (int i = 1; i <= n;i++)
    {
        ans = min(ans, dis[(1 << (n+1))-1][i]);
    }
    printf("%.2lf", ans);
    return 0;
}

B (1320) : 上色

利用multiset自带的二分找到大于当前数的位置,如果不存在则直接插入,删除该数并插入当前的数,每个数就相当于一个序列里的最大的数,最后输出set的大小即为满足的序列的个数。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=2e5+10,INF=1e9;
int a[N];
int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    int n;
    while(cin>>n)
    {
        multiset<int> st;
        for (int i = 1; i <= n;i++)
            cin >> a[i];
        for (int i = 1; i <= n;i++)
        {
            auto t = st.lower_bound(a[i]);
            if(t==st.begin())
            {
                st.insert(a[i]);
            }
            else
            {
                t--;
                st.erase(t);
                st.insert(a[i]);
            }
        }
        cout << st.size()<<'\n';
    }

    return 0;
}

C (1321) : 第k小

二分+二分,第一次二分是找当前第k小的数,第二次二分是二分是看这个数是否满足第k小,将整个分为小于0和大于等于0这两部分,二分负的有多少对乘积小于x再二分正的,最后再二分正的和负的,需要注意负数二分需要revese,因为两个负数相乘越小乘完越大,最后正负相乘的时候也需要注意。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=2e5+10,INF=1e9;
vector<ll> a, b;
ll n, k;
bool check(ll x)
{
    ll ans = 0;
    sort(a.begin(), a.end(),greater<ll>());
    sort(b.begin(), b.end());
    int n = a.size(), m = b.size();
    for (int i = 0; i < n;i++)
    {
        ll l = i, r = n-1;
        while(l<r)
        {
            ll mid = l + r + 1>> 1;
            if(a[i]*a[mid]<=x)
            {
                l = mid;
            }
            else
                r = mid - 1;
        }
        if(l>i)ans += l - i;
    }

    for (int i = 0; i < m;i++)
    {
        ll l = i, r = m-1;
        while(l<r)
        {
            ll mid = l + r+1>> 1;
            if(b[i]*b[mid]<=x)
            {
                l = mid;
            }
            else
                r = mid - 1;
        }
        if(l>i) ans += l - i;
    }
    reverse(a.begin(), a.end());
    reverse(b.begin(), b.end());
    for (int i = 0; i < n;i++)
    {
        ll l = -1, r = m - 1;
        while(l<r)
        {
            ll mid = l + r +1 >> 1;
            if(a[i]*b[mid]<=x)
            {
                //res = mid;
                l = mid;
            }
            else
                r = mid - 1;
        }
        if(l!=-1) ans += l + 1;
    }
    return ans >= k;
}
int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    cin >> n >> k;
    for (int i = 1; i <= n;i++)
    {
        ll x;
        cin >> x;
        if(x<0)
            a.push_back(x);
        else
            b.push_back(x);
    }
    ll l = -1e18, r = 1e18 ;
    sort(a.begin(), a.end(),greater<ll>());
    sort(b.begin(), b.end());
    while(l<r)
    {
        ll mid = l + r >> 1;
        if(check(mid))
        {
            r = mid;
        }
        else
            l = mid + 1;
    }
    cout << l;
    return 0;
}

Codeforces Round #640 (Div. 4)

A. Sum of Round Numbers

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e9;
int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    int t;
    cin >> t;
    while(t--)
    {
        string n;
        cin>>n;
        int cnt = 0;
        reverse(n.begin(), n.end());
        for (int i = 0; i <n.size();i++)
        {
            if(n[i]!='0')
            {
                cnt++;
            }
        }
        cout << cnt << '\n';
        for (int i = 0; i < n.size(); i++)
        {
            if(n[i]!='0')
            {
                int x = n[i] - '0';
                cout << x * (pow(10,i)) << ' ';
            }
        }
        cout << '\n';
    }
    return 0;
}

B. Same Parity Summands

留出最后一个数,如果当前数能被分成若干的2或1相加,最后再加上留出的数就行,否则不行

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e9;
int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--)
    {
        int n, k;
        cin>>n>>k;
        k--;
        int cnt1 = n - k, cnt2 = n - 2 * k;
        if(cnt2%2==0&&cnt2>0)
        {
            cout << "YES" << '\n';
            for (int i = 1; i <= k;i++)
            {
                cout << '2' << ' ';
            }
            cout << cnt2 << '\n';
        }
        else if(cnt1&1&&cnt1>0)
        {
            cout << "YES" << '\n';
            for (int i = 1; i <= k;i++)
            {
                cout << '1' << ' ';
            }
            cout << cnt1 << '\n';
        }
        else
            cout << "NO" << '\n';
    }

    return 0;
}

C. K-th Not Divisible by n

如果不能被n整除说明前面n-1个肯定是一组的只有n被拿掉了,我们可以根据k里有多少个(n-1)这样的组,因此为ans*n。如果cnt为0说明最后一个数整除了,因此需要去掉。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e9;
int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--)
    {
        ll n,k;
        cin >> n >> k;
        ll ans = k / (n - 1);
        ll cnt = k % (n - 1);
        if(cnt!=0)
        {
            cout << ans * n + cnt<<'\n';
        }
        else
        {
            cout << ans * n - 1<<'\n';
        }
    }

    return 0;
}

D. Alice, Bob and Candies

模拟

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e3+10,INF=1e9;
int a[N];
int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin >> n;
        int sum = 0;
        for (int i = 1; i <= n;i++)
        {
            cin >> a[i];
            sum += a[i];
        }
        int cnt=0 ,sum1=0, sum2 = 0,now=0;
        for (int i = 1; i <= n;)
        {
            cnt++;
            int sum = a[i++];
            while(sum<=now&&i<=n)
                sum += a[i++];
            sum1 += sum;
            now = sum;
            if(i>n)
                break;
            cnt++;
            sum = a[n--];
            while(sum<=now&&i<=n)
                sum += a[n--];
            sum2 += sum;
            now=sum;
        }
        cout << cnt << ' ' << sum1 << ' ' << sum2 << '\n';
    }

    return 0;
}

E. Special Elements

问你区间是否存在某段连续的段其和为数组的任意一个数ai。求出满足的ai的个数。利用双指针,枚举每个点为开头,sum不断吗相加直到超过n,(因为最大的ai不超过n),每次加一个数的时记录sum,如果sum在之前出现过那么对答案贡献为1否则为0,每次加完之后都要清空,防止重复。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=8000+10,INF=1e9;
int a[N],vis[N];
int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        memset(vis, 0, sizeof vis);
        for (int i = 1; i <= n;i++)
        {
            cin >> a[i];
            vis[a[i]]++;
        }
        int ans = 0;
        for (int i = 1; i < n;i++)
        {
            int sum = a[i];
            for (int j = i + 1; j <= n;j++)
            {
                sum += a[j];
                if(sum>n)
                    continue;
                ans += vis[sum];
                vis[sum] = 0;
            }
        }
        cout << ans << '\n';
    }

    return 0;
}

F. Binary String Reconstruction

给你n0,n1,n2,表示01字符串01的和,让你构造出该字符串。
如果当n1为0的话我们可以直接构造出n0和n2的情况,只需在n0的基础上多输出一个0即可。
当n1不为0的时候我们首先构造出n1个10在加1个0或1.然后在第一个0之前补充n0个0,第一个1之前补充n1个1,因为此时已经包含有一个1和一个0了,因此不需要额外输出

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e9;
int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--)
    {
        int sum0, sum1, sum2;
        cin >> sum0>> sum1>>sum2;
        if(sum1==0)
        {
            if(sum0)
            {
                for (int i = 1; i <= sum0+1;i++)
                {
                    cout << '0';
                }
            }
            if(sum2)
            {
                for (int i = 1; i <= sum2+1;i++)
                {
                    cout << '1';
                }
            }
            cout << '\n';
            continue;
        }
        string s;
        for (int i = 1; i <= sum1 + 1;i++)
        {
            if(i&1)
            {
                s += '1';
            }
            else
                s += '0';
        }
        s.insert(1, string(sum0, '0'));
        s.insert(0, string(sum2, '1'));
        cout << s << '\n';
    }

    return 0;
}

G. Special Permutation

想的比较复杂去了,思维还是不够。其实两个偶数或奇数都是差2,只需要从大到小输出奇数,最后再加上4和2保证差在2-4之间,然后再从大到小输出偶数就行了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e9;
int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin >> n;
        if(n<4)
        {
            cout << "-1" << '\n';
            continue;
        }
        for (int i = n; i >= 1;i--)
        {
            if(i&1)
                cout << i << ' ';
        }
        cout << "4 2 ";
        for (int i = 6; i <= n;i+=2)
        {
            cout << i << ' ';
        }
        cout << '\n';
    }

    return 0;
}
posted @ 2022-04-10 16:57  menitrust  阅读(39)  评论(0编辑  收藏  举报