Codeforces 871 div4(重拳出击)
Codeforces 871 div4
ABC
简单题
D
题意
每次操作可以将当前的数分成两份,一份是,一份是,问当前数n可否进行若干次操作,最终出现一份大小为m的片。递归一下就好了,数据最大才
代码
void dfs(int x)
{
if(x==m) {flag=1;return;}
if(flag) return;//找到了就不用再递归了
if(x%3) return;
dfs(x/3*2);
dfs(x/3);
}
void solve()
{
flag=0;
cin>>n>>m;
if(n<m) {cout<<"NO\n";return;}
if(n==m){cout<<"YES\n";return;}
if(n%3) {cout<<"NO\n";return;}
flag=0;
dfs(n);
if(flag) {cout<<"YES\n";}
else cout<<"NO\n";
}
E (FloodFill)
题意
经典dfs了
代码
int n,m,k;
int ans,tmp;
int a[1100][1100];
bool vis[1100][1100];
int flag=0;
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
int sum=0;//能遍历到的点的总和
void dfs(int x,int y)
{
for(int i=0;i<4;i++)
{
int nx=x+dx[i],ny=y+dy[i];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&a[nx][ny]&&!vis[nx][ny])
{
vis[nx][ny]=1;
sum+=a[nx][ny];
dfs(nx,ny);
}
}
}
void solve()
{
cin>>n>>m;
ans=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++) cin>>a[i][j],vis[i][j]=0;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(!vis[i][j]&&a[i][j])
{
vis[i][j]=1;
sum=a[i][j];
dfs(i,j);
ans=max(ans,sum);
}
}
}
cout<<ans<<endl;
}
F
题意
题目给出一个雪花图,从根节点延伸出x个子节点,每个子节点又延伸出y个子节点
思路
先扫一遍树统计一下每个点的子节点个数,然后再扫一遍遍历就ok了。注意x和y都大于1
代码
int n,m,k;
int ans,tmp;
int h[N],e[N*2],ne[N*2],idx;
int cnt[N],cnt1[N];
int x=-1,y=-1;
void add(int a,int b)
{
e[idx]=b;
ne[idx]=h[a];
h[a]=idx++;
}
void dfs(int u,int fa)
{
cnt[u]=1;
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(j==fa) continue;
dfs(j,u);
cnt[u]+=cnt[j];
}
}
void dfs1(int u,int fa)
{
if(x>1) return;//找到直接返回
int tmp=-1,flag=1;
if(u==1) //特判根节点,因为它没有父节点,不用考虑父亲的那棵树的情况
{
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(j==fa) continue;
if(tmp==-1) tmp=cnt[j];
if(tmp!=cnt[j]) {flag=0;break;}
}
}
else
{
tmp=n-cnt[u];//父亲那颗树的大小
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(j==fa) continue;
if(tmp!=cnt[j]) {flag=0;break;}
}
}
if(flag==1)
{
int c1=0;
for(int i=h[u];i!=-1;i=ne[i])
{
c1++;
}
if(c1>1) x=c1,y=(n-c1-1)/x;
}
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(j==fa) continue;
dfs1(j,u);
}
}
void solve()
{
memset(h,-1,sizeof(h));
idx=0;
cin>>n>>m;
for(int i=1;i<=n;i++) cnt[i]=0,cnt1[i]=0;
for(int i=1;i<=m;i++)
{
int a,b;
cin>>a>>b;
add(a,b);
add(b,a);
}
if(n==2) {cout<<1<<" "<<0<<endl;return;}
dfs(1,-1);
x=-1,y=-1;
dfs1(1,-1);
cout<<x<<" "<<y<<endl;
}
G
题意
一个金字塔,然后把某个块搞垮,与它上表面接触的块也会搞垮,依次类推,问搞垮某个块,垮掉的块的总贡献是多少。块n的贡献为
思路
一开始想的很复杂,又分左右情况去讨论,记忆化搜索好像又不可行。后来想着暴力,过啦。
暴力思路:用个f数组记录每个数的位置。
代码
int f[2010][2010],g[2010][2010];
void init()
{
int x=1;
for(int i=1;i<=2000;i++)
{
for(int j=1;j<=i;j++)
{
f[i][j]=x*x;
x++;
}
}
}
int x,y;
void get(int n)
{
x=1;
while(n>x) n-=x,x++;
y=n;
}
void solve()
{
cin>>n;
get(n);//获取n的位置
int ans=0;
int k=1;
while(x)
{
for(int i=max(0ll,y-k+1);i<=y;i++) ans+=f[x][i];
x--,k++;
}
cout<<ans<<endl;
}
H(补)
题意
给了一个长度为n的数组,问有多少个不为空的子数组,它们的与的结果是只有k个1.
思路
dp。设状态为前i个数能构成结果j的方案。
转移方程:
代码
int n,m,k;
int ans,tmp;
int a[N],f[64];
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=0;i<64;i++) f[i]=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=63;j++) //j&a[i]<=j,正着来
{
f[j&a[i]] = (f[j&a[i]]+f[j]%mod)%mod;
if(j==a[i]) f[j]=(f[j]+1)%mod;
}
}
int ans=0;
for(int i=0;i<64;i++)
{
int cnt=0;
for(int j=0;j<=6;j++) if((i>>j)&1) cnt++;
if(cnt==m) ans=(ans+f[i])%mod;
}
cout<<ans<<endl;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)