1. 程式人生 > 其它 >abc 247 題解

abc 247 題解

A - Move Right

給一個四位的二進位制,輸出右移一位的結果

#include <bits/stdc++.h>
using namespace std;

int n;
string s ;

int main()
{
    cin >> s;
    cout << '0';
    for( int i = 0 ; i <= 2 ; i ++ )
        cout << s[i];
}

B - Unique Nicknames

每一個人都有一個姓和一個名,要給每個人取一個暱稱

暱稱要滿足兩個條件,首先暱稱必修與姓或名相同,其次暱稱不能與其他人的姓或名相同

實際上把所有的所有的名和姓塞入到一個 map 中,只要一個人的名或姓是唯一的那麼他就是可以起一個暱稱

注意的是,會有人的名和姓相同

#include <bits/stdc++.h>
using namespace std;

int n;
map<string , int> st;
string a[105] , b[105];

int main()
{
    cin >> n;
    for( int i = 1 ; i <= n ; i ++ ) {
        cin >> a[i] >> b[i];
        st[a[i]] ++ ;
        if( a[i] != b[i] ) st[b[i]] ++;
    }
    for( int i = 1 ; i <= n ; i ++ )
    {
        if( st[a[i]] == 1 || st[b[i]] == 1) continue;
        printf("No\n");
        return 0;
    }
    printf("Yes\n");
    return 0;
}

C - 1 2 1 3 1 2 1

題目給定了一個構造字串的方法,\(s_i=s_{i-1}is_{i-1}\)

因為 n 很小直接構造就好

#include <bits/stdc++.h>
using namespace std;

int n;
string s[20];

int main()
{
    cin >> n;
    s[1] = "1";
    for( int i = 2 ; i <= n ; i ++ )
        s[i] = s[i-1] + " " + to_string(i) + " " + s[i-1];
    cout << s[n];
    return 0;
}

D - Cylinder

首先給一個佇列,然後有兩種操作

  1. 插入 c 個 x
  2. 取出 c 個數並求和

如果單純的模擬的話會 t,所以佇列中存的是一個pair表示數和數的個數

然後每次我們取出一個pair如果有剩餘的數就插回到隊頭,所以這裡要用到雙端佇列

#include <bits/stdc++.h>
#define ll long long
using namespace std;

ll n , cnt;
deque< pair<ll,ll> > dq;

int read(){
    int x = 0 , f = 1 , ch = getchar();
    while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
    if( ch == '-' ) f = -1 , ch = getchar();
    while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
    return x*f;
}

int main() {
    n = read();
    for( ll op , m , x , c ; n ; n -- ) {
        op = read();
        if (op == 1)
            x = read(), c = read(), dq.push_back({x, c});
        else {
            m = read(), cnt = 0;
            while (m) {
                x = dq.front().first, c = dq.front().second, dq.pop_front();
                if (c <= m)
                    cnt += x * c, m -= c;
                else
                    cnt += x * m , dq.push_front({x, c - m}) , m = 0;
            }
            printf("%lld\n", cnt);
        }
    }
    return 0;
}

E - Max Min

給定長度為 n 的序列,問有多少個區間的最大值最小值是 x 和 y

首先列舉一下左端點,然後二分出符合條件的最小值和最大值即可

那麼如何判區間時候符合條件呢?實際上就是用線段樹來維護一下區間最值就好了

#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int N = 2e5+5;
int n , maxx , miny , a[N] ;
ll cnt ;

struct Node{
    int l , r , maxval , minval;
    Node *left , *right;
    Node( int l , int r , int maxval , int minval , Node * left , Node * right ) : l(l) , r(r) , maxval(maxval) , minval(minval) , left(left) , right(right){};
} *root;

Node * build( int l , int r )
{
    if( l == r ) return new Node( l , r , a[l] , a[l] , 0 , 0 );
    int mid = ( l + r ) >> 1;
    Node * left = build( l , mid ) , * right = build( mid + 1 , r );
    return new Node( l , r , max( left -> maxval , right -> maxval) , min( left -> minval , right -> minval ) , left , right );
}

void query( int l , int r , Node * cur , int &maxval , int &minval )
{
    if( l == cur -> l && r == cur ->r )
    {
        maxval = max( maxval , cur -> maxval ) , minval = min( minval , cur -> minval );
        return ;
    }
    int mid = ( cur -> l + cur -> r ) >> 1;
    if( l > mid ) query( l , r , cur -> right , maxval , minval );
    else if( r <= mid ) query( l , r , cur -> left , maxval , minval );
    else query( l , mid , cur -> left , maxval , minval ) , query( mid + 1 , r , cur -> right , maxval , minval );
}

ll erfen1( int x ){
    int l = x , r = n , mid , res = -1, maxval , minval;
    while( l <= r ){
        mid = (l+r)>>1 , maxval = -1 , minval = 0x7fffffff;
        query( x , mid , root , maxval , minval );
        if( maxval >= maxx && minval <= miny ) res = mid , r = mid - 1;
        else l = mid + 1;
    }
    if( res == -1 ) return -1;
    maxval = -1 , minval = 0x7fffffff , query( x  , res , root , maxval , minval );
    if(maxval == maxx && minval == miny ) return res;
    return -1;
}

ll erfen2( int x ){
    int l = x , r = n , mid , res = -1, maxval , minval;
    while( l <= r ){
        mid = (l+r)>>1 , maxval = -1 , minval = 0x7fffffff;
        query( x , mid , root , maxval , minval );
        if( maxval <= maxx && minval >= miny ) res = mid , l = mid + 1;
        else r = mid - 1;
    }
    if( res == -1 ) return -1;
    maxval = -1 , minval = 0x7fffffff , query( x  , res , root , maxval , minval );
    if(maxval == maxx && minval == miny ) return res;
    return -1;
}

int read(){
    int x = 0 , f = 1 , ch = getchar();
    while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
    if( ch == '-' ) f = -1 , ch = getchar();
    while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
    return x*f;
}

int main() {
    n = read() , maxx = read() , miny = read();
    for( int i = 1 ; i <= n ; i ++ ) a[i] = read();
    root = build(1,n);
    for( ll i = 1 , l , r ; i <= n ; i ++ ){
        l = erfen1( i ) , r = erfen2(i);
        if( l != -1 && r != -1 ) cnt += r - l + 1;
    }
    cout << cnt << endl;
    return 0;
}