牛客算法周周练2
A
看到要去前导0,直接字符串模拟了,倒着的时候从第一个不为0的数字开始计算这个数字大小,加上原来数字即可
#include
using namespace std;
typedef long long ll;
int main(){
char s[10];
cin>>s;
int sum=0;
for(int i=0;i<strlen(s);i++) sum=sum*10+s[i]-'0';
int flag=0;
int a=0;
for(int i=strlen(s)-1;i>=0;i--){
if(s[i]!='0'){
flag=1;
}
if(flag){
a=a*10+s[i]-'0';
}
}
cout<<sum+a<<endl;
return 0;
}B
问题:将一些数字取任意个相加能不能拼凑出3600的倍数,就是背包有无解的问题。
两种做法。
第一种:直接bitset优化.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
int t;cin>>t;
while(t--){
int n;cin>>n;
bitset<3600> q;
for(int i=1;i<=n;i++){
int x;cin>>x;
x%=3600;
//右端第一部分是说已经有的基础上再加一个x, 第二部分是溢出3600的部分取余
q |= (q << x) | (q >> (3600-x));
q[x]=1;//将x添加上去
}
if(q[0]) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
感谢评论区hx073269大哥指正 第二种是个假算法 复杂度爆掉了 应该是数据水了。当然有兴趣的可以看下?(狗头
第二种,想一下,如果n≥3600一定有解,为什么?证明如下:
设
如果对于n个sum取余3600后,余数在0到3599之间都有位置,显然有解。
如果在0~3599有的位置没有,说明至少存在两个位置的sum%3600后的值一样,那么区间的一段就是3600的倍数。得证。
所以n≥3600 直接输出YES
否则跑个背包判断有无解。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
int t;cin>>t;
while(t--){
int n;cin>>n;
vector<int> a(n+1);
for(int i=1;i<=n;i++) cin>>a[i];
if(n>=3600) cout<<"YES"<<endl;
else
{
vector<vector<int>> dp(n+1,vector<int>(3600));
dp[0][0]=1;
for(int i=0;i<n;i++){
for(int j=0;j<3600;j++){
if(dp[i][j]){
dp[i+1][j]+=dp[i][j];
dp[i+1][(j+a[i+1])%3600]+=dp[i][j];
}
}
}
if(dp[n][0]>1) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
return 0;
}C
判断l到r之间有多少个完全平方数,然后判断端点l是不是完全平方数即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
int n;
cin>>n;
while(n--)
{
ll l,r;
cin>>l>>r;
ll s1=sqrt(l)+0.000001,s2=sqrt(r)+0.000001;
ll num=s2-s1;
if(s1*s1==l) num++;
cout<<num<<endl;
}
return 0;
}D
考虑开一个二维数组cnt[n][3]
cnt[i][0]表示i受到的波及次数,
cnt[i][1]表示i对儿子节点的波及次数
cnt[i][2]表示i对孙子节点的波及次数
那么对于每次询问,i肯定对i的儿子和孙子造成了波及,所以cnt[i][1]++,cnt[i][2]++
那么往上考虑,i也对他父亲和爷爷造成了波及所有 cnt[f[i]][0]++,cnt[f[f[i]][0]++
还有一点要注意,i本身和i的同父亲的兄弟也会收到波及,那么这里我们要怎么加呢?直接加到i的父亲节点对儿子节点的波及即可,也就是cnt[f[i]][1]++,这样就同时加入了i本身和他兄弟受到的影响
那么对于每个点i,受到的波及次数就是cnt[1][0]+cnt[f[i]][1]+cnt[f[f[i]][2]
即自身收到子节点的波及次数+父亲对自己的波及次数+爷爷对自己的波及次数
所以dfs求出每个点的父亲后按照上述过程模拟即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1<<20;
vector<int>e[maxn];
int cnt[maxn][3];///自己、儿子、孙子
int f[maxn];
void dfs(int x,int fa){
f[x]=fa;
for(auto it:e[x]){
if(it==fa) continue;
dfs(it,x);
}
}
int main(){
ios::sync_with_stdio(0);
int n,m;cin>>n>>m;
for(int i=1;i<n;i++){
int a,b;cin>>a>>b;
e[a].push_back(b);
e[b].push_back(a);
}
dfs(1,0);
f[0]=maxn-1;
while(m--){
int a;cin>>a;
cnt[a][1]++,cnt[a][2]++;
cnt[f[a]][1]++,cnt[f[a]][0]++;
cnt[f[f[a]]][0]++;
cout<<cnt[a][0]+cnt[f[a]][1]+cnt[f[f[a]]][2]<<endl;
}
return 0;
}
E
E题中的式子其实就是斐波那契数列的几何意义
其实就是问n是不是斐波那契数,是的话输出它的阶乘在m进制下有多少个0,质因数分解完事。
不是的话,就是问1~13皇后有多少种分布方式。
懒得写了。。(其实是太菜了) 还是补了一下
枚举m的质因子i,然后去看x!中有多少个i,我们只需要取最小即可。13皇后?表打出来即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[]={-1, 1, 0, 0, 2, 10, 4, 40, 92, 352, 724, 2680, 14200, 73712};
ll inf=1e18;
ll f[5005];
int main(){
int cnt;
f[1]=f[2]=1;
for(cnt=3;;cnt++){
f[cnt]=f[cnt-1]+f[cnt-2];
if(f[cnt]>=inf) break;
}
ll x,m;cin>>x>>m;
int flag=0;
for(int i=1;i<=cnt;i++) {
if(f[i]==x){
flag=1;
break;
}
}
if(flag){
ll ans=1e18;
for(int i=2;i*i<=m;i++){
if(m%i==0){
ll num=0;
while(m%i==0) m/=i,num++;
ll num1=0;
ll y=x;
while(y) num1+=y/i,y/=i;
ans=min(ans,num1/num);
}
}
if(m!=1) {
ll num=0;
while(x) num+=x/m,x/=m;
ans=min(ans,num);
}
cout<<ans<<endl;
}
else cout<<a[x%min(13ll,m)+1];
return 0;
}

查看11道真题和解析