Codeforces Round #721 (Div. 2)

Codeforces Round #721 (Div. 2) 

来源:https://codeforces.com/contest/1527

 

A. And Then There Were K

不妨打一个表看看有没有什么规律.  

发现每个数字 $\mathrm{x}$ 的答案是 $\mathrm{x}$ 二进制展开中最高次位减一.    

直接对每个数 $O( \log n) $ 扫一下即可.  

#include <cstdio>
#include <cstring>
#include <algorithm> 
#define ll long long 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;
ll calc(ll x) {
    for(int i=32;i>=0;--i) {
        if(x&(1ll<<i)) {
            return (1ll<<i)-1;  
        }
    }
} 
int main() {
    // setIO("input");   
    int T; 
    scanf("%d",&T); 
    while(T--) {
        ll n ; 
        scanf("%lld",&n); 
        printf("%lld\n",calc(n)); 
    }
    return 0; 
}

  

B1 - Palindrome Game (easy version)

此版本的串为回文串.   

假如 0 的个数为偶数,则后手可以一直模仿先手.  

剩 2 个数时,先手将 $0$ 变 $1$ 后使用一次跳步,可以少取 2 次.   

假如 0 的个数为奇数,且只有一个 0 则后手胜,否则先手胜. 

这是因为先手可以先取中间的 0,然后转化成一个偶数的子问题.  

先手在第一步吃亏一步,后面后手吃亏 2 步,先手胜.   

#include <cstdio>
#include <vector>
#include <cstring>  
#define N 10007 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std; 
char str[N]; 
void solve() {
    int n ; 
    scanf("%d",&n); 
    scanf("%s",str+1);    
    int cnt=0; 
    for(int i=1;i<=n;++i) if(str[i]=='0') ++cnt;           
    if(cnt > 1 && (cnt % 2 == 1))   printf("ALICE\n"); 
    else printf("BOB\n"); 
}
int main() {
    // setIO("input"); 
    int T; 
    scanf("%d",&T); 
    while(T--) solve(); 
    return 0; 
}

  

B2. Palindrome Game (hard version)

假设最开始不是回文串:   

如果长度为偶数,则先手可以一直使用跳步,后手要凑成回文串.  

在差一步能凑成回文串时先手走那一步,然后就变成 B1 中长度为偶数先手必败子问题了.  

故 ALICE 获胜.

若长度为奇数,则要看中间位置是否为 0.  

若中间位置为 1,则与偶数情况无异,ALICE 获胜.     

若中间位置为 0,则先手走中间位置后又变成上面 ALICE 获胜子问题.   

唯一使得 ALICE 不胜的情况就是中间位置为 0,且一共只有两个 0.  

这样 ALICE 走完第一步后 BOB 走完第二步两者就打平了.    

#include <cstdio>
#include <vector>
#include <cstring>  
#define N 10007 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std; 
char str[N]; 
void solve() {
    int n ; 
    scanf("%d",&n); 
    scanf("%s",str+1);    
    int cnt=0; 
    int flag=0; 
    for(int i=1;i<=n;++i) {
        if(str[i]=='0') ++cnt;           
        if(str[i] != str[n-i+1]) flag=1;   
    }
    if(!flag) {
        if(cnt > 1 && (cnt % 2 == 1))   printf("ALICE\n"); 
        else printf("BOB\n"); 
    }
    else {
        if(n % 2 == 1 && str[(1+n)/2] == '0' && cnt == 2) printf("DRAW\n"); 
        else printf("ALICE\n");   
    }
}
int main() {
    // setIO("input"); 
    int T; 
    scanf("%d",&T); 
    while(T--) solve(); 
    return 0; 
}

  

C.Sequence Pair Weight

将每一种数字单独提取出来并单独计算贡献.  

枚举右端点,然后每一个左端点的贡献就是该左端点的位置.   

扫一遍即可.   

#include <cstdio> 
#include <cstring>
#include <algorithm>
#include <vector>  
#define N  100009 
#define ll long long 
#define pb push_back 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;
vector<int>v[N];
int a[N],A[N],n;  
void solve() {
    scanf("%d",&n);    
    for(int i=1;i<=n;++i) scanf("%d",&a[i]), A[i]=a[i]; 
    sort(A+1,A+1+n);  
    for(int i=1;i<=n;++i) {
        a[i]=lower_bound(A+1,A+1+n,a[i])-A;  
        v[a[i]].pb(i); 
    }
    ll ans=0ll; 
    for(int i=1;i<=n;++i) {
        if(v[i].size() < 2) continue;  
        ll sum=0ll; 
        for(int j=0;j<v[i].size();++j) {
            ans += 1ll*(n - v[i][j] + 1) * sum;   
            sum += v[i][j];  
        }
    }
    printf("%lld\n",ans);  
    for(int i=1;i<=n;++i) {
        v[i].clear(); 
    }
} 
int main() { 
    // setIO("input");  
    int T; 
    scanf("%d",&T); 
    while(T--) solve(); 
    return 0; 
}

  

D.MEX Tree

直接做肯定不好做.   

根据 $\mathrm{mex}$ 的定义,若 $\mathrm{mex=i}$, 则路径需要包含 $1$ ~ $\mathrm{i-1}$, 且不包含 $\mathrm{i}$

上一篇:java内存分析


下一篇:P5675