牛牛爱字符串

题意:给出一个字符串,提取出这个字符串中的所有的数字,然后依次输出这些数字。
思路:简单模拟。但是这里要注意的是不能有前导0,还有全为0的情况输出即可。
代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    string s;
    while(getline(cin,s)){
        string ans[1000];
        int len=s.size();
        int num=0;
        for(int i=0;i<len;i++){
            if(s[i]<='9'&&s[i]>='0')  ans[num]+=s[i];
            if(i>0){
                if(s[i-1]<='9'&&s[i-1]>='0'&&(s[i]<'0'||s[i]>'9')) num++; 
            }
        }
        if(s[len-1]>='0'&&s[len-1]<='9')  num++;
        for(int i=0;i<num;i++){
            len=ans[i].size();
            int j;
            for(j=0;j<len;j++){
                if(ans[i][j]!='0') break;
            }
            for(;j<len;j++){
                cout<<ans[i][j];
            }
            if(i<num-1)  cout<<" ";
        }
        cout<<endl;
    }
    return 0;
}

牛牛爱位运算

题意:给出一个数组,求数组里面的所有的数且之后的最大值。
思路:对于每个数字写出它的二进制表示后,我们会发现且之后1&1=1,1&0=0,0&1=0,0&0=0,那么我们就想,如果我们要求最大的话,如果这个位置为0的话,那么它无论如何都不会成为1,如果为1的话,它很可能会变成0。最后下来,我们得到一个结论就是找出最大的那个值就是本题的答案了。
代码:

#include<bits/stdc++.h>
using namespace std;
int a[100010];
int main(){
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        int mx=-1;
        for(int i=0;i<n;i++){
            cin>>a[i];
            mx=max(mx,a[i]);
        }
        cout<<mx<<endl;
    }
    return 0;
}

牛牛爱博弈

题意:一共有n堆棋子,两人轮流取石子,但是要求取的数量必须为2^k次方,取走最后一颗石头的那一方获胜。
思路:经过模拟,我们发现1,2对先手方为必赢态,而3对后手方为必赢态(因为先手会把石头拿成对后手有利的那个局面,对于此时的局面,先手方变为后手方。然后4,5对先手方为必赢态,6对后手方为必赢态。这样模拟下来的话,我们发现,n为3的倍数的话后手方赢,否则为先手方赢。
代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        if(n%3==0)  cout<<"Frame"<<endl;
        else  cout<<"Alan"<<endl;
    }
    return 0;
}

牛妹爱数列

题意:给出一个01序列,然后对这个序列可以进行一下两种操作,1、反转序列中的某个序列的值(0或1),2、反转前x个序列的值(0或1),问最小的操作数使得最后的序列变成全0.
思路:一个很显然的dp的思想。我们用一个二维dp数组表示对这个序列进行处理的步数最小。dp[i][0]表示的是前i个数全变成0的所需的最小的数。dp[i][1]表示这个序列全部变成1所需的最小的操作数。当我们遍历到这个序列的i时,如果此时的a[i]为1的话,那么dp[i][0]就可以向min(dp[i-1][0]+1,dp[i-1][1]+1)转移,dp[i][1]可以向min(dp[i-1][1],dp[i-1][0]+1)转移。同理a[i]=0的时候类似的进行转移即可。
代码:

#include<bits/stdc++.h>
using namespace std;
int a[100010];
int dp[100010][2];
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)  cin>>a[i];
    for(int i=1;i<=n;i++){
        if(a[i]){
            dp[i][0]=min(dp[i-1][1]+1,dp[i-1][0]+1);
            dp[i][1]=min(dp[i-1][1],dp[i-1][0]+1);
        }else{
            dp[i][0]=min(dp[i-1][1]+1,dp[i-1][0]);
            dp[i][1]=min(dp[i-1][1]+1,dp[i-1][0]+1);
        }
    }
    cout<<dp[n][0]<<endl;
    return 0;
}

牛妹游历城市

题意:给出n个节点,然后每个结点都有一个值,这两个结点之间有无连边取决于两者的且值,如果不为0表示这两个点之间有一天连边,然后这条边的权值为lowbit(a[i]&a[j])。
思路:我们发现,当务之急就是先将这n个点连接起来,但是我们会发现点的数量太多了,怎么办呢?我们看题目出现了&这个符号,那么我们很显然可以往位运算那方面考虑。我们观察数据都是在int范围内的,那么我们就对这n个点的a进行一个处理,提取出这n个数的位进制位,然后遍历这32位二进制就可以实现判断这两个点之间是否存在连边。同时我们建立若干个虚点来方便找出存在连边的那些点,也就是我们把在第j位(1<=j<32)为1的a[i]存放在一个结构体里面,然后两者相互映射,当我们遍历到i的时候,我们可以通过映射找到存储与之存在连边的点的那个结构体,这样我们就可以快速的找到存在连边的那些点了(这个方法确实十分的巧妙666)然后跑一遍Dijkstra即可。
代码:

#include<bits/stdc++.h>
#define lowbit(x) (x&)-x)
using namespace std;
typedef long long ll;
const int N=1e5+100;
ll a[N],dis[N],len;
int book[N],s=1,t,n;
struct node{
    int v;
    ll val;
};
vector<node> e[N];
void solve(){
    queue<int> q;
    memset(book,0,sizeof(book));
    q.push(s);
    book[s]=1;
    dis[s]=0;
    while(!q.empty()){
        int x=q.front();
        q.pop();
        book[x]=0;
        for(int i=0;i<e[x].size();i++){
            node to=e[x][i];
            if(dis[to.v]>dis[x]+to.val){
                dis[to.v]=dis[x]+to.val;
                if(book[to.v]==0){
                    q.push(to.v);
                    book[to.v]=1;
                }
            }
        }
    }
    if(dis[n]!=1e18)  cout<<dis[n]<<endl;
    else  cout<<"Impossible"<<endl;
}
int main(){
    cin>>t;
    while(t--){
        cin>>n;
        for(int i=1;i<=n+50;i++){
            e[i].clear();
            dis[i]=1e18;
        }
        for(int i=1;i<=n;i++)  cin>>a[i];
        for(int i=1;i<=n;i++){
            for(int j=0;j<32;j++){
                if(a[i]&(1ll<<j)){  //二进制下的第j位为1的话 
                    e[i].push_back({n+1+j,1ll<<j});
                    e[n+1+j].push_back({i,0});
                }
            }
        }
        solve();
    }
    return 0;
}