阿里4-12笔试,看别人发的题写的答案,有注释
第一题
#include <iostream> #include <vector> #include <string> #include <deque> #include <unordered_map> #include <algorithm> #include <unistd.h> #include <fcntl.h> using namespace std; string s;//每个节点是什么颜色 vector<vector<int>> tree;//树 vector<pair<int,int>> dp;//记录每个节点下有多少R B pair<int,int> dfs(int u){ //无子节点直接返回自己含有的RB数量 if(tree[u].size()==0){ dp[u] = {s[u]=='R',s[u]=='B'}; return dp[u]; } //记忆化搜索 if(dp[u].first!=-1){ return dp[u]; } pair<int,int> res{s[u]=='R',s[u]=='B'};//先加上自己节点的RB数量 for(auto v:tree[u]){//加上子节点的RB数量 auto&& cntv = dfs(v); res.first += cntv.first; res.second += cntv.second; } //记忆化搜索 if(dp[u].first==-1){ dp[u] = res; } return res; } int main(){ //输入重定向 int fd = open("../test.txt",O_RDONLY); dup2(fd,0); int n; cin>>n; cin>>s; tree.resize(n); dp.resize(n,{-1,-1}); for(int i=0;i<n-1;++i){ int u,v; cin>>u>>v; tree[u-1].emplace_back(v-1);//u父v子 - u子v父也可以,正反都一样就一个连接关系 } //计算每个节点下的R B数 for(int u=0;u<n;++u){ dfs(u); } //计算所有点下的R B pair<int,int> allRB; for(auto c:s){ if(c=='R') ++allRB.first; else ++allRB.second; } //遍历删除每个点的父边 int res=0; for(int v=0;v<n;++v){ pair<int,int>& vRB = dp[v]; pair<int,int> alldelv{allRB.first - vRB.first,allRB.second - vRB.second}; //判断主树删了子v后,和子v,分别是否符合条件 if(alldelv.first > alldelv.second && vRB.first > vRB.second){ ++res; } } cout<<res; return 0; }
第二题
#include <iostream> #include <vector> #include <string> #include <deque> #include <unordered_map> #include <algorithm> #include <unistd.h> #include <fcntl.h> using namespace std; int main(){ //输入重定向 int fd = open("../test.txt",O_RDONLY); dup2(fd,0); int n; int cnt[32]={0};//所有数每位上1的个数和 cin>>n; for(int i=0;i<n;++i){ uint32_t num; cin>>num; for(int pos=0;pos<=31;++pos){ if(((uint32_t)1<<pos)&num)//统计每1位1的个数,累加到cnt cnt[pos] += 1; } } int res=0; for(int pos=0;pos<=31;++pos){ res += min(n-cnt[pos],cnt[pos]); } cout<<res; return 0; }
第三题
#include <iostream> #include <vector> #include <string> #include <unistd.h> #include <fcntl.h> using namespace std; int dp[100001][3];//dp[i][j]代表以i位为结尾,余数为j的串个数 int s[100001];//存每一位数字 int main(){ //输入重定向 int fd = open("../test.txt",O_RDONLY); dup2(fd,0); string ss; cin>>ss; int n=ss.length(); int sum=0; for(int i=0;i<n;++i){ s[i]=ss[i]-'0'; sum+=s[i]; } int need = sum%3;//sum为3n需要删除区间内余数为0,3n+1需要删除区间内余数为1,3n+2需要删除区间内余数为2 。问题简化为对删除区间内的余数要求。 int res = 0; //删结尾[i,n-1],讨论前一位i-1是5的倍数,且被删除部分对3余数是need int suffix=0; for(int i=n-1;i>0;--i){ suffix+=s[i]; if(s[i-1]%5==0 && suffix%3==need){ ++res; } } //保留末尾的情况,如果末尾是5或者0那只看前面是否是是3的倍数就行了 if(s[n-1]%5==0){ dp[0][0] = s[0]%3==0; dp[0][1] = s[0]%3==1; dp[0][2] = s[0]%3==2; for(int i=1;i<n;++i){ if(s[i]%3==0){ dp[i][0] = dp[i-1][0]+1;//加自己本身也算一个 dp[i][1] = dp[i-1][1]; dp[i][2] = dp[i-1][2]; }else if(s[i]%3==1){ dp[i][0] = dp[i-1][2]; dp[i][1] = dp[i-1][0]+1; dp[i][2] = dp[i-1][1]; }else{ dp[i][0] = dp[i-1][1]; dp[i][1] = dp[i-1][2]; dp[i][2] = dp[i-1][0]+1; } } //最后一位不删 for(int i=0;i<n-1;++i){ res += dp[i][need]; } } cout<<res; return 0; }