Codeforces Round #744 (Div. 3) A-F 题解

在这里插入图片描述
第一次接近前百纪念

这次的题意就不再赘述了
大概说一下方法

A. Casimir’s String Solitaire

思路
每次都有B
B的数量等于A和C的和即可
时间复杂度 O n On On

#include <bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define der(i,a,b) for(re i = a ; i >= b ; -- i)
#define all(x) (x).begin(),(x).end()
#define de(x) cout << x << "\n" 
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int> 
#define re register int
#define int long long 
#define pb push_back
#define y second 
#define x first 
using namespace std;
const int inf = 0x3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f ;
const int N = 1e6 + 10 , M = 2010 , mod = 1e9 + 7 ;

signed main()
{
    int t ;
    cin >> t ;
    
    while(t--)
    {
        string a ;
        
        int kb = 0 , k = 0 ;
        
        cin >> a ;
        
        for(auto i : a) 
        {
            if(i == 'B') kb ++ ;
            else k ++ ;
        }
        
        if(kb == k) puts("YES") ;
        else puts("NO") ;
    }
    return 0;
}

B. Shifting Sort

思路
倒着做
每次找到最大的一个数,放到最后即可
注意序列是动态的 不过n很小
直接暴力
时间复杂度 O n 2 On^2 On2

#include <bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define der(i,a,b) for(re i = a ; i >= b ; -- i)
#define all(x) (x).begin(),(x).end()
#define de(x) cout << x << "\n" 
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int> 
#define re register int
#define int long long 
#define pb push_back
#define y second 
#define x first 
using namespace std;
const int inf = 0x3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f ;
const int N = 60 , M = 2010 , mod = 1e9 + 7 ;
 
int n ;
int a[N] ;
int b[N] ;
int c[N] ;
 
struct ai{
    int l , r , d ;
}q[N] ;
 
signed main()
{
    int t ;
    cin >> t ;
    while(t--)
    {
        cin >> n ;
        
        fer(i,1,n) sf(a[i]) ;
        
        fer(i,1,n) b[i] = a[i] ;
        
        sort(b + 1 , b + 1 + n) ;
        
        int hh = 0 ;
        
        der(i,n,1)
        {
            int k = 0;
            for(int j = i ; j >= 1 ; j --)
            {
                if(a[j] == b[i])
                {
                    k = j ;
                    break ;
                }
            }
            if(k != 0 && k != i)
            {
                q[++ hh] = {k,i,1} ;
                
                fer(i,1,k-1) c[i] = a[i] ;
                fer(i,k,n-1) c[i] = a[i+1] ;
                c[n] = a[k] ;
                memcpy(a,c,sizeof c) ;
            }
        }
        
        cout << hh << '\n' ;
        fer(i,1,hh) cout << q[i].l << " " << q[i].r << " " << q[i].d << "\n" ;
        
    }
    return 0;
}

C. Ticks

思路
模拟一下就行
时间复杂度 O n m k Onmk Onmk

#include <bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define der(i,a,b) for(re i = a ; i >= b ; -- i)
#define all(x) (x).begin(),(x).end()
#define de(x) cout << x << "\n" 
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int> 
#define re register int
#define int long long 
#define pb push_back
#define y second 
#define x first 
using namespace std;
const int inf = 0x3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f ;
const int N = 1e6 + 10 , M = 50 , mod = 1e9 + 7 ;
 
int n, m, k;
char s[M][M];
bool st[M][M];
 
bool check(int x, int y)
{
	if(x < 0 || x >= n || y < 0 || y >= m) return 0 ;
	else return 1 ;
}
 
void get(int x, int y)
{
	int l = 0, r = 0;
 
	while (check(x - l, y - l) && s[x - l][y - l] == '*')
		l ++;
	while (check(x - r, y + r) && s[x - r][y + r] == '*')
		r ++;
 
	l --;
	r --;
	if (min(l, r) >= k) {
		for (int i = 0; i <= min(l, r); i++) {
			st[x - i][y - i] = 1;
			st[x - i][y + i] = 1;
		}
	}
}
 
void solve()
{
    cin >> n >> m >> k;
    
	memset(st, 0, sizeof st);
	
	fer(i,0,n-1)
		scanf("%s", s[i]);
 
	fer(i,0,n-1)
		fer(j,0,m-1)
			if (s[i][j] == '*')
				get(i, j);
 
	bool w = 1;
	fer(i,0,n-1)
		fer(j,0,m-1)
			if (s[i][j] == '*' && st[i][j] == 0)
				w = 0;
 
	if (w)
		puts("YES") ;
	else
		puts("NO") ;
}
signed main()
{
	int t ;
	cin >> t ;
	while (t--) 
	{
		solve() ;
	}
	return 0;
}

D. Productive Meeting

思路
注意到a[i]的总和是2e5
直接大根堆每次取出最大的2个- -即可

其实这题是以前cf的原题
问的是不输出方案的最大值
记录最大值和总和比较一下即可on

其实每次取出最大的2个不一定是对的
(因为给不出证明)
其实我是想用set取出一大一小一定是对的

但是已经写完了优先队列就不想改了
时间复杂度 O n l o g n Onlogn Onlogn

#include <bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define der(i,a,b) for(re i = a ; i >= b ; -- i)
#define all(x) (x).begin(),(x).end()
#define de(x) cout << x << "\n" 
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int> 
#define re register int
#define int long long 
#define pb push_back
#define y second 
#define x first 
using namespace std;
const int inf = 0x3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f ;
const int N = 1e6 + 10 , M = 2010 , mod = 1e9 + 7 ;

int t ;
int n ;
int a[N] ;
pll ans[N] ;

signed main()
{
    cin >> t ;
    
    while(t--)
    {
        cin >> n ;
    
        int s = 0 ;
        
        priority_queue<pll> q ;
        
        fer(i,1,n)
        {
            sf(a[i]) ;
            if(a[i]) q.push({a[i],i}) ;
        }
        
        int hh = 0 ;
        
        while(q.size() >= 2)
        {
            auto t1 = q.top() ;
            q.pop() ;
            
            auto t2 = q.top() ;
            q.pop() ;
            
            ans[ ++ hh] = {t1.y,t2.y} ;
            
            t1.x -- , t2.x -- ;
            if(t1.x) q.push({t1.x,t1.y}) ;
            if(t2.x) q.push({t2.x,t2.y}) ;
        }
        
        de(hh) ;
        
        fer(i,1,hh)
        {
            cout << ans[i].x << " " << ans[i].y << "\n" ;
        }
    }
    return 0;
}

E1. Permutation Minimization by Deque

思路
用duque直接模拟
小的放前面,大的放后面即可
时间复杂度 O n On On

#include <bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define der(i,a,b) for(re i = a ; i >= b ; -- i)
#define all(x) (x).begin(),(x).end()
#define de(x) cout << x << "\n" 
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int> 
#define re register int
#define int long long 
#define pb push_back
#define y second 
#define x first 
using namespace std;
const int inf = 0x3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f ;
const int N = 1e6 + 10 , M = 2010 , mod = 1e9 + 7 ;
 
int t ;
int n ;
int a[N] ;
 
signed main()
{
    cin >> t ;
    
    while(t--)
    {
        cin >> n ;
        
        fer(i,1,n) sf(a[i]) ;
        
        deque<int> q;
		q.push_back(a[1]);
 
		for (int i = 2; i <= n; i++)
			if (a[i] < q.front())
				q.push_front(a[i]);
			else
				q.push_back(a[i]);
 
		while (!q.empty()) {
			printf("%lld ", q.front());
			q.pop_front();
		}
		puts("") ;
    }
    return 0;
}

E2. Array Optimization by Deque

思路
如果一个数放前面,代价是后面所有比它小的数的个数
如果一个数放后面,代价是前面所有比它大的数的个数

其实我们可以发现跟放的顺序无关

每次求出放前面的代价
和放后面的代价
哪个小就加那个

可以用树状数组动态维护
因为树状数组下标必须从1开始
所以离散化一下即可

时间复杂度 O n l o g n Onlogn Onlogn

#include <bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define der(i,a,b) for(re i = a ; i >= b ; -- i)
#define all(x) (x).begin(),(x).end()
#define de(x) cout << x << "\n" 
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int> 
#define re register int
#define int long long 
#define pb push_back
#define y second 
#define x first 
using namespace std;
const int inf = 0x3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f ;
const int N = 1e6 + 10 , M = 2010 , mod = 1e9 + 7 ;
 
int t ;
int n ;
int a[N] ;
int tr[N] ;
 
int lowbit(int x)
{
    return x & -x ;
}
int sum(int x)
{
    long long res = 0 ;
    for(int i = x ; i ; i -= lowbit(i)) res += tr[i] ;
    return res;
}
void add(int x , int c)
{
    for(int i = x ; i <= n ; i += lowbit(i)) tr[i] += c ;  
}
 
signed main()
{
    cin >> t ;
    
    while(t--)
    {
        cin >> n ;
        
        vector<int> q ;
        
        fer(i,1,n) sf(a[i]) , q.pb(a[i]) ;
        
        sort(all(q)) ;
        q.erase(unique(q.begin(),q.end()),q.end()) ;
        
        fer(i,1,n) a[i] = lower_bound(all(q),a[i]) - q.begin() + 1 ;
        
        // fer(i,1,n) cout << a[i] << " " ;
        // puts("") ;
        
        fer(i,1,n) tr[i] = 0 ;
        
        int res = 0 ;
        
        fer(i,1,n)
        {
            int hh = sum(a[i] - 1) , tt = sum(n) - sum(a[i]);
            
            //cout << hh << " " << tt << "\n" ;
            
            if(hh <= tt)
            {
                res += hh ;
                add(a[i],1) ;
            }
            else 
            {
                res += tt ;
                add(a[i],1) ;
            }
        }
        
        de(res) ;
    }
    return 0;
}

F. Array Stabilization (AND version)

思路
这种题一般先找性质

首先如果有0的话那么这个地方对应的位置是0还是1我们已经不关心了
因为这个位置一定一直都是0
因为0&1 = 0 0&0 = 0

然后我们发现题目给的d的意思是
每次0会向后面移动 (i + d) % n (假设0的下标是i)

那么如果(i + d) % n这个位置已经是0的话
那么i这个位置就没有意义了
因为后面的0会更新后面所有步数的答案
这个0就可以舍弃了

如果(i + d) % n这个位置是1的话
那就把它变成0

然后不断重复上述过程

我们可以用bfs/优先队列来维护
每次取出步数最小的下标
然后不断重复上述过程

因为每个点最多只被遍历一次
所以时间复杂度为nlogn
时间复杂度 O n l o g n Onlogn Onlogn

#include <bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define der(i,a,b) for(re i = a ; i >= b ; -- i)
#define all(x) (x).begin(),(x).end()
#define de(x) cout << x << "\n" 
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int> 
#define re register int
#define int long long 
#define pb push_back
#define y second 
#define x first 
using namespace std;
const int inf = 0x3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f ;
const int N = 1e6 + 10 , M = 2010 , mod = 1e9 + 7 ;
 
int t ;
int n , d ;
int a[N] ;
 
signed main()
{
    cin >> t ;
    
    while(t--)
    {
        cin >> n >> d ;
        
        fer(i,0,n-1) sf(a[i]) ;
        
        int res = 0 ;
        
        priority_queue< pll , vector<pll> , greater<pll>> q ;
        
        fer(i,0,n-1)
        {
            if(a[i] == 0) q.push({0,i}) ;
        }
        
        while(q.size())
        {
            auto t = q.top() ;
            q.pop() ;
            
            int x = (t.y + d) % n ;
            if(a[x] == 0) continue ;
            else
            {
                a[x] = 0 ;
                q.push({t.x+1,x}) ;
                res = max(res,t.x+1) ;
            }
        }
        
        int f1 = 0 ;
        fer(i,0,n-1) 
        {
            if(a[i] == 1) f1 = 1 ;
        }
        
        if(!f1)
            de(res) ;
        else puts("-1") ;
    }
    return 0;
}
  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值