牛客练习赛67 题解报告(未完成)

比赛链接

A 牛牛爱字符串

思路分析:模拟题。
需要注意的是如果将字符串中所有数字提取出来的话,若数字长度过大,很容易溢出。建议直接确定数字在字符串中的首尾位置后遍历输出。

C o d e : Code: Code:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include 
using namespace std;
#define MaxN 100010
//#define MOD 998244353
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define endl '\n'
#define LL long long
#define PII pair
#define rint register int 
#define ULL unsigned long long
const int MOD=1e9+7;
//int days[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
//int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
template<class T> inline void read(T& x){
    x=0;int f=0;char ch=getchar();
    while( !isdigit(ch) ) f|=( ch == '-' ) , ch=getchar();
    while( isdigit(ch) )  x = ( x<<1 ) + ( x<<3 ) + ( ch^48 ) , ch=getchar();
    x = f ? -x : x;
}
template<class T> inline void print(T x){
    if ( x < 0 ) { putchar('-'); x = -x; }
    if ( x >= 10 ) print( x / 10 );
    putchar(x % 10 + '0');
}
char str[MaxN];
void solve(){
    int n=strlen(str);
    for(int i=0; i<n; i++){
        if( isdigit(str[i]) ){
            int j=i;
            while( j < n && isdigit(str[j+1]) ) j++;
            while( i < j && str[i] == '0' ) i++;
            for(int k=i; k<=j; k++) cout<<str[k];
            cout<<' ';
            i=j;
        }
    }
    cout<<endl;
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    while( gets(str) ){
        solve();
    }
    return 0; 
}

B 牛牛爱位运算

思路分析:结论题。
a & b < = max ⁡ ( a , b ) a \& b <= \max(a,b) a&b<=max(a,b) 拓展到 n n n 个数字也是一样。

C o d e : Code: Code:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include 
using namespace std;
#define MaxN 1000010
//#define MOD 998244353
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define endl '\n'
#define LL long long
#define PII pair
#define rint register int 
#define ULL unsigned long long
const int MOD=1e9+7;
//int days[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
//int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
template<class T> inline void read(T& x){
    x=0;int f=0;char ch=getchar();
    while( !isdigit(ch) ) f|=( ch == '-' ) , ch=getchar();
    while( isdigit(ch) )  x = ( x<<1 ) + ( x<<3 ) + ( ch^48 ) , ch=getchar();
    x = f ? -x : x;
}
template<class T> inline void print(T x){
    if ( x < 0 ) { putchar('-'); x = -x; }
    if ( x >= 10 ) print( x / 10 );
    putchar(x % 10 + '0');
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int T;
    cin>>T;
    while( T-- ){
        int ans=-INF,n,m;
        cin>>n;
        for(int i=1; i<=n; i++){
            cin>>m;
            ans=max(ans,m);
        }
        cout<<ans<<endl;
    }
    return 0; 
}

C 牛牛爱博弈

思路分析:思维题。
我们每次只能取 2 k {2}^k 2k颗石子。如果对 2 k {2}^k 2k m o d mod mod 3 3 3 的话,就是 1 , 2 , 1 , 2 , 1 , 2 , … 1 ,2,1,2,1,2,\ldots 1,2,1,2,1,2,.我们发现这个数列是以 1 , 2 1,2 1,2循环的。那么原题意就可以转化为取若干次石子,每次只能取 3 3 3颗石子和一次取 1 , 2 1,2 1,2颗石子的操作。取走最后一个石子的算赢。
如果当 n n n 3 3 3的倍数的话,先手无法一次性取完,必然要剩下部分石子,我们设 n = 3 k 1 n=3{k_1} n=3k1,经过先手操作后的剩余石子为 3 k 1 − 3 k 2 − 1 3{k_1}-3{k_2}-1 3k13k21或者是 3 k 1 − 3 k 2 − 2 3{k_1}-3{k_2}-2 3k13k22,整理后发现对于 3 ( k 1 − k 2 ) − 2 3{(k_1-k_2)}-2 3(k1k2)2或者 3 ( k 1 − k 2 ) − 1 3{(k_1-k_2)-1} 3(k1k2)1,后手只要分别取 1 , 2 1,2 1,2颗石子,就能确保下一轮留给先手的石子个数为 3 3 3的倍数。先手依旧无法取走最后一颗石子,所以无法必胜。
n n n不是 3 3 3的倍数,先手可以先取走 1 1 1颗或者 2 2 2颗,这样留给后手的石子个数就会是 3 3 3的倍数。后手无法一次性取走所有的石子,必然会剩余石子,留到下一轮。重复上述操作,可确保先手必胜。
结论: n n n 3 3 3的倍数则后手必胜,反之则先手必胜。

C o d e : Code: Code:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include 
using namespace std;
#define MaxN 100010
//#define MOD 998244353
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define endl '\n'
#define LL long long
#define PII pair
#define rint register int 
#define ULL unsigned long long
const int MOD=1e9+7;
//int days[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
//int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
template<class T> inline void read(T& x){
    x=0;int f=0;char ch=getchar();
    while( !isdigit(ch) ) f|=( ch == '-' ) , ch=getchar();
    while( isdigit(ch) )  x = ( x<<1 ) + ( x<<3 ) + ( ch^48 ) , ch=getchar();
    x = f ? -x : x;
}
template<class T> inline void print(T x){
    if ( x < 0 ) { putchar('-'); x = -x; }
    if ( x >= 10 ) print( x / 10 );
    putchar(x % 10 + '0');
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int T;
    cin>>T;
    while( T-- ){
        LL n;
        cin>>n;
        if( n%3 ) cout<<"Alan"<<endl;
        else cout<<"Frame"<<endl; 
    }
    return 0; 
}

D 牛牛爱数列

思路分析:线性 d p dp dp
题意很像线性 d p dp dp中的经典例题最短编辑距离,都是给定一个字符串和几种操作方案,问最少经过多少次操作,可变成要求的字符串。
那么考虑 d p dp dp做法。
d p [ i ] [ 0 / 1 ] dp[i][0/1] dp[i][0/1]分别为前 i i i位全 0 0 0和全 1 1 1的最少操作次数。
如果当前 A [ i ] = = 0 A[i]==0 A[i]==0的话,显然有 d p [ i ] [ 0 ] = m i n ( d p [ i − 1 ] [ 0 ] , d p [ i − 1 ] [ 1 ] + 1 ) dp[i][0]=min(dp[i-1][0],dp[i-1][1]+1) dp[i][0]=min(dp[i1][0],dp[i1][1]+1),此处的 d p [ i − 1 ] [ 1 ] + 1 dp[i-1][1]+1 dp[i1][1]+1意思是先将前 i − 1 i-1 i1位翻转为 1 1 1,最后利用前缀修改操作使得前 i i i位全 0 0 0,同时显然有 d p [ i ] [ 1 ] = m i n ( d p [ i − 1 ] [ 0 ] + 1 , d p [ i − 1 ] [ 1 ] + 1 ) dp[i][1]=min(dp[i-1][0]+1,dp[i-1][1]+1) dp[i][1]=min(dp[i1][0]+1,dp[i1][1]+1),两个 + 1 +1 +1分别对应前缀修改和单点修改。
同理,当前 A [ i ] = = 1 A[i]==1 A[i]==1的话,显然有 d p [ i ] [ 1 ] = m i n ( d p [ i − 1 ] [ 0 ] + 1 , d p [ i − 1 ] [ 1 ] ) dp[i][1]=min(dp[i-1][0]+1,dp[i-1][1]) dp[i][1]=min(dp[i1][0]+1,dp[i1][1]),同时显然有 d p [ i ] [ 0 ] = m i n ( d p [ i − 1 ] [ 0 ] + 1 , d p [ i − 1 ] [ 1 ] + 1 ) dp[i][0]=min(dp[i-1][0]+1,dp[i-1][1]+1) dp[i][0]=min(dp[i1][0]+1,dp[i1][1]+1)
最终答案为 d p [ n ] [ 0 ] dp[n][0] dp[n][0]

C o d e : Code: Code:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include 
using namespace std;
#define MaxN 100010
//#define MOD 998244353
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define endl '\n'
#define LL long long
#define PII pair
#define rint register int 
#define ULL unsigned long long
const int MOD=1e9+7;
//int days[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
//int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
template<class T> inline void read(T& x){
    x=0;int f=0;char ch=getchar();
    while( !isdigit(ch) ) f|=( ch == '-' ) , ch=getchar();
    while( isdigit(ch) )  x = ( x<<1 ) + ( x<<3 ) + ( ch^48 ) , ch=getchar();
    x = f ? -x : x;
}
template<class T> inline void print(T x){
    if ( x < 0 ) { putchar('-'); x = -x; }
    if ( x >= 10 ) print( x / 10 );
    putchar(x % 10 + '0');
}
int A[MaxN],dp[MaxN][2];
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int n;
    cin>>n;
    for(int i=1; i<=n; i++) cin>>A[i];
    for(int i=1; i<=n; i++){
        if( A[i] == 0 ){
            dp[i][0]=min(dp[i-1][0],dp[i-1][1]+1);
            dp[i][1]=min(dp[i-1][0]+1,dp[i-1][1]+1);
        }
        else{
            dp[i][0]=min(dp[i-1][0]+1,dp[i-1][1]+1);
            dp[i][1]=min(dp[i-1][0]+1,dp[i-1][1]);
        }
    }
    cout<<dp[n][0];
    return 0; 
}

你可能感兴趣的:(题解)