2022.3.9

蓝书

AcWing 106. 动态中位数

思路:对顶堆,设第一个数为mid,之后的数读进来一次比较大小决定放入大根堆还是小根堆,然后当i为奇数的时候输出当前的中位数。
注意一下格式问题,当中位数的个数不能整除10的时候最后还要加个换行。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
const int N=1e5+10,INF=1e8;
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        int n, m,cnt=1;
        scanf("%d%d", &n, &m);
        printf("%d %d\n", n, m / 2 + 1);
        priority_queue<int> mmax;
        priority_queue<int, vector<int>, greater<int> > mmin;
        int x,mid;
        scanf("%d", &x);
        printf("%d ", x);
        mid = x;
        for (int i = 2; i <= m;i++)
        {
            scanf("%d", &x);
            if(x>mid)
                mmin.push(x);
            else
                mmax.push(x);
            if(i%2==1)
            {
                while(mmax.size()!=mmin.size())
                {
                    if(mmax.size()>mmin.size())
                    {
                        mmin.push(mid);
                        mid = mmax.top();
                        mmax.pop();
                    }
                    else if(mmax.size()<mmin.size())
                    {
                        mmax.push(mid);
                        mid = mmin.top();
                        mmin.pop();
                    }
                }
                printf("%d ", mid);
                cnt++;
                if(cnt%10==0)
                printf("\n");
            }
        }
        if(cnt%10!=0)
           printf("\n");
    }
    return 0;
}

AcWing 107. 超快速排序

思路:归并排序求逆序对

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=5e5+10,INF=1e8;
int a[N],tmp[N];
ll cnt;
void mergesort(int l,int r)
{
    if(l>=r)
        return;
    int mid = l + r >> 1;
    mergesort(l,mid);
    mergesort(mid + 1, r);
    int i = l, j = mid + 1,k=0;
    while(i<=mid&&j<=r)
    {
        if(a[i]<=a[j])
            tmp[k++] = a[i++];
        else
            {
            tmp[k++] = a[j++];
            cnt += mid - i + 1;
        }
    }
    while(i<=mid)
        tmp[k++] = a[i++];
    while(j<=r)
        tmp[k++] = a[j++];
    for (int i = l, j = 0; i <= r;i++,j++)
        a[i] = tmp[j];
}
int main()
{
    int n;
    while(scanf("%d",&n)&&n)
    {
        cnt = 0;
        for (int i = 1; i <= n;i++)
            scanf("%d", &a[i]);
        mergesort(1, n);
        printf("%lld\n", cnt);
    }
    return 0;
}

AcWing 108. 奇数码问题

两个局面可达,当且仅当两个局面的逆序对的积偶性相同。当空格左右移动的时候是不会改变原本序列的顺序的,只要当上下移动的时候才会改变,也就是与前或后的n-1个数位置互换,因为n为奇数,所以n-1即逆序对个数的变化只能为偶数

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=250010,INF=1e8;
int a[N],b[N],tmp[N];
ll cnt;
void mergesorta(int l,int r)
{
    if(l>=r)
        return;
    int mid = l + r >> 1;
    mergesorta(l,mid);
    mergesorta(mid + 1, r);
    int i = l, j = mid + 1,k=0;
    while(i<=mid&&j<=r)
    {
        if(a[i]<=a[j])
            tmp[k++] = a[i++];
        else
            {
            tmp[k++] = a[j++];
            cnt += mid - i + 1;
        }
    }
    while(i<=mid)
        tmp[k++] = a[i++];
    while(j<=r)
        tmp[k++] = a[j++];
    for (int i = l, j = 0; i <= r;i++,j++)
        a[i] = tmp[j];
}
void mergesortb(int l,int r)
{
    if(l>=r)
        return;
    int mid = l + r >> 1;
    mergesortb(l,mid);
    mergesortb(mid + 1, r);
    int i = l, j = mid + 1,k=0;
    while(i<=mid&&j<=r)
    {
        if(b[i]<=b[j])
            tmp[k++] = b[i++];
        else
            {
            tmp[k++] = b[j++];
            cnt += mid - i + 1;
        }
    }
    while(i<=mid)
        tmp[k++] = b[i++];
    while(j<=r)
        tmp[k++] = b[j++];
    for (int i = l, j = 0; i <= r;i++,j++)
        b[i] = tmp[j];
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        cnt = 0;
        int num = 1;
        for (int i = 1; i <= n*n;i++)
        {
            int x;
            scanf("%d", &x);
            if(x)
                a[num++] = x;
        }
        num = 1;
        for (int i = 1; i <= n*n;i++)
        {
            int x;
            scanf("%d", &x);
            if(x)
                b[num++] = x;
        }
        mergesorta(1, num);
        ll ans = cnt;
        cnt = 0;
        mergesortb(1, num);
        if((ans&1)==(cnt&1))
            printf("TAK\n");
        else
            printf("NIE\n");
    }
    return 0;
}

AcWing 177. 噩梦

按照蓝书的思路来实现就行,先拓展鬼的占领范围,因为男孩和女孩都可以移动所以要有2个bfs,我们判断能遇见的因素是当bfs女孩的时候枚举女孩走的点,如果男孩走过当前点那说明他们就可以在最短的时间相遇了。直接返回即可。
有几个小坑点:每次都要先更新一下鬼的和人的曼哈顿距离,枚举3次男孩的步数的时候别忘了枚举的点的个数不能超过队列里的点,女孩同理。还有就是枚举女孩的点的时候不能把判断的visb放在for循环的外面,因为这样就不能保证女孩是第一次符合visb了,稍微理解一下。一开始甚至sb的把dis数组也加上了,后面发现根本没必要,然后就是写着写着容易忘记更新vis,得时刻警记。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N=800+10,INF=1e8;
char mp[N][N];
int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, 1, -1};
int n,m,tt,g1x,g1y,g2x,g2y;
int visb[N][N], visg[N][N];
queue <PII> boy,girl;
bool check(int x,int y)
{
    return (x >= 1 && x <= n && y >= 1 && y <= m && mp[x][y] != 'X' && (abs(x - g1x) + abs(y - g1y) > 2 * tt )&& (abs(x - g2x) + abs(y - g2y) > 2 * tt));
}
int bfs()
{
    tt = 0;
    memset(visb, 0, sizeof visb);
    memset(visg, 0, sizeof visg);
    while(boy.size()||girl.size())
    {
        tt++;
        for (int i = 1; i <= 3;i++)
        {
            int bcnt = boy.size();
            for (int k = 1; k <= bcnt;k++)
            {
                auto b = boy.front();
                boy.pop();
                int x = b.first, y = b.second;
                 if(visb[x][y]&&visg[x][y])
                    return tt;
                if(!check(x,y))
                    continue;
                visb[x][y] = 1;
                for (int j = 0; j < 4;j++)
                {
                    int xx = x + dx[j], yy = y + dy[j];
                    if(check(xx,yy)&&!visb[xx][yy])
                    {
                        visb[xx][yy] = 1;
                        boy.push({xx, yy});
                    }
                }
            }
        }
        int gcnt = girl.size();
        for (int i = 1; i <= gcnt;i++)
        {
            auto g = girl.front();
            girl.pop();
            int x = g.first, y = g.second;
            // if(visb[x][y]&&visg[x][y])这样是错的
            //      return tt;
            if(!check(x,y))
                continue;
            visg[x][y] = 1;
            for (int i = 0; i < 4;i++)
            {
                int xx = x + dx[i], yy = y + dy[i];
                 if(check(xx,yy)&&!visg[xx][yy])
                {
                    if(visb[xx][yy])
                        return tt;
                    girl.push({xx, yy});
                    visg[xx][yy] = 1;
                }
            }
        }
    }
    return -1;
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        int cnt=0;
        while(boy.size())
          boy.pop();
        while(girl.size())
          girl.pop();
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n;i++)
        {
          for (int j = 1; j <= m;j++)
          {
            cin >> mp[i][j];
            if(mp[i][j]=='M')
            {
              boy.push({i, j});
              visb[i][j] = 1;
            }
            else if(mp[i][j]=='G')
            {
              girl.push({i, j});
              visg[i][j] = 1;
            }
            else if(mp[i][j]=='Z')
            {
                if(cnt==1)
                {
                    g2x = i, g2y = j;
                }
                else
                    g1x = i, g1y = j;
                cnt++;
            }
          }
        }
        int ans=bfs();
        printf("%d\n", ans);
    }
    return 0;
}

Codeforces Round #776 (Div. 3)

A. Deletions of Two Adjacent Letters

题意:给你一个长度为奇数字符串s和一个字母c,你可以通过删除相邻字母来减少字符串的长度,问最后字符串是否有可能变成字母c
思路:对于字符串找一下是否存在一个奇数位该位为字母c。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=1e5+10,INF=1e8;
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        int n,f=0;
        scanf("%d", &n);
        char s[55]={0},x;
        scanf("%s", s+1);
        cin >> x;
        int len = strlen(s + 1);
        for (int i = 1; i <= len;i++)
        {
            if(s[i] == x&&(i%2==1))
            {
                f = 1;
                break;
            }
        }
        if(f)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}

B. DIV + MOD

题意:在给定的区间[l,r]里找一个数满足这个数整除x和模x的和最大
贪心,首先这个值最小也得是r/x+r%x,但为了让模的数更大我们需要找接近x的数如:x-1,x-2...如此就有模的最大值,x-1%x。于是我们需要在区间找这样一个值x=r/a*a-1。如果r<a的话那么这个值x就是-1,如果r>a的话,如果a的某个整数倍-1,最后再和最小值的答案比较一下。
有点迷糊,看了红黑的代码稍微理解了一点

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=1e5+10,INF=1e8;
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        int l, r, x;
        scanf("%d%d%d", &l, &r, &x);
        int ans = r / x + r % x;
        int res = r / x * x - 1;
        if(res>=l)
            ans = max(ans, res / x + res % x);
        printf("%d\n", ans);
    }
    return 0;
}

C.Weight of the System of Nested Segments

题意:给你一个x轴,上面m个点,点有坐标和权值,你需要找到n个区间满足区间是从大到小包含的,从外到内一层套一层。
思路:先排序一下点的权值,然后选2*n个点组成n个区间,然后排序一下他们的x轴坐标,最后按照各自最开始的位置输出。
甚至比B好想一点

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=2e5+10,INF=1e8;
struct node
{
    ll id,x,w;
}a[N];
bool cmp(node a,node b)
{
    return a.w<b.w;
}
bool cmp1(node a,node b)
{
    return a.x<b.x;
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        int n, m;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= m; i++)
        {
            scanf("%lld%lld", &a[i].x, &a[i].w);
            a[i].id = i;
        }
        ll sum=0;
        sort(a+1,a+1+m,cmp);
        sort(a+1,a+1+2*n,cmp1);
        for(int i=1;i<=2*n;i++)
            sum += a[i].w;
        printf("%lld\n", sum);
        for(int i=1;i<=n;i++)
            printf("%lld %lld\n", a[i].id, a[2 * n - i + 1].id);
    }
    return 0;
}
posted @ 2022-03-09 14:01  menitrust  阅读(15)  评论(0编辑  收藏  举报