牛牛爱字符串
题意:给出一个字符串,提取出这个字符串中的所有的数字,然后依次输出这些数字。
思路:简单模拟。但是这里要注意的是不能有前导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; }