Codeforces Beta Round #9 (Div. 2 Only)

18 篇文章 0 订阅
4 篇文章 0 订阅

*C. Hexadecimal's Numbers

theme:给定数字n,求[1,n]中只由字符0或1构成的数字个数。1<=n<=1e9

solution :只由01组成的数为:

1

10 11

100 101 110 111

1000 1001 1010 1011 1100 1101 1110 1111...

可以看出下一行为上一行每个数*10或*10+1的结果。所以我们可以从1开始递归,每次在当前数的基础上*10,*10+1,直到>n结束。

相当于预处理出从小到大的范围内满足条件的值然后lower_bound()找到n所处位置即可。

#include<bits/stdc++.h>
#include<vector>
#include<algorithm>
using namespace std;
#define far(i,t,n) for(int i=t;i<n;++i)
#define pk(a) push_back(a)
typedef long long ll;
typedef unsigned long long ull;
using namespace std;

int ans=0;
ll n;

void cnt(ll x)
{
    if(x>n)
        return;
    ++ans;
    cnt(x*10);
    cnt(x*10+1);
}

int main()
{
    cin>>n;
    cnt(1);
    cout<<ans<<endl;
}

D. How many trees?

theme:给定n与h,求所有n个节点的二叉树中,高度<=h(包含根节点及叶子节点)的个数。

solution:用dp[i][j]表示i个节点的二叉树,高度<=h的个数,则状态转移方程为

dp[i][j]=\sum (dp[k][j-1]*dp[i-1-k][j-1]) , 0<=k<i

由转移方程知每个数是前一列若干数两两相乘,所以要一列一列地算,循环时j在外层循环,初始化所有dp[0][j]=1

#include<bits/stdc++.h>
#include<vector>
#include<algorithm>
using namespace std;
#define far(i,t,n) for(int i=t;i<n;++i)
#define pk(a) push_back(a)
typedef long long ll;
typedef unsigned long long ull;
using namespace std;

ll dp[40][40];

void getDp(int n)
{
    for(int i=0;i<=n;++i)
        dp[0][i]=1;
    for(int j=1;j<=n;++j)
    {
        for(int i=1;i<=n;++i)
            for(int k=0;k<i;++k)
            {
                dp[i][j]+=dp[k][j-1]*dp[i-k-1][j-1];
            }
    }
}

int main()
{
    int n,h;
    cin>>n>>h;
    getDp(n);
    ll ans=dp[n][n]-dp[n][h-1];
    cout<<ans<<"\n";
}

E. Interesting Graph and Apples

theme:给定n个点和m条边,要求最终达到每个节点都属于且只属于一个经过所有节点的环,问最少还要添加多少条边 。

solution:由题意知最终要形成一个环,所以最终所有节点的度都为2。用并查集,

首先将输入的图形存入并查集形成多个连通分量。并记录每个节点的度。判断是否有度>2的点,直接输出NO。

否则从小到大遍历每个节点,若该节点度<2,则将它与最小的度<2且与它不在同一个并查集的点相连,遍历一遍后整个图将变成一条链。

连接两个度为1的端点,此时形成了一个大环。

最后再判断一下所有节点是不是属于同一个并查集,避免形成多个环。

注意可以由自圈与重边。

#include<bits/stdc++.h>
#include<vector>
#include<algorithm>
using namespace std;
#define far(i,t,n) for(int i=t;i<n;++i)
#define pk(a) push_back(a)
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
 
int fa[100];
int degree[100];
vector<pair<int,int>>ans;
 
void init(int n)
{
    for(int i=0; i<=n; ++i)
        fa[i]=i;
}
 
int Find(int x)
{
    return fa[x]==x?x:fa[x]=Find(fa[x]);
}
 
void unit(int x,int y)
{
    x=Find(x);
    y=Find(y);
    fa[y]=x;
}
 
int main()
{
    int n,m;
    while(cin>>n>>m)
    {
        ans.clear();
        memset(degree,0,sizeof(degree));
        init(n);
        far(i,0,m)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            degree[x]++;
            degree[y]++;
            unit(x,y);
        }
        far(i,1,n+1)
        if(degree[i]>2)
        {
            cout<<"NO\n";
            return 0;
        }
        //连成一条链
        far(i,1,n+1)
        {
            far(j,i+1,n+1)
                if(degree[j]<=1&&degree[i]<=1&&Find(i)!=Find(j))
                {
                    degree[j]++;
                    degree[i]++;
                    unit(i,j);
                    ans.push_back({i,j});
                }
        }
        far(i,1,n+1)
        if(degree[i]>2)
        {
            cout<<"NO\n";
            return 0;
        }
        //连端点成环
        int s=0,e=0;
        far(i,1,n+1)
        {
             if(degree[i]<=1)
            {
                if(!s)
                    s=e=i;
                else
                {
                    if(i!=s)
                    {
                        if(e==s)
                            e=i;
                    }
                }
            }
        }
        if(s!=0&&e!=0)
        {
            ans.push_back({s,e});
            unit(s,e);
            degree[s]++;
            degree[e]++;
        }
        for(int i=1; i<=n; ++i)
            if(Find(i)!=Find(1)||degree[i]!=2)
            {
 
                cout<<"NO\n";
                return 0;
            }
        cout<<"YES\n";
        int sz=ans.size();
        cout<<sz<<"\n";
        sort(ans.begin(),ans.end());
        far(i,0,sz)
        printf("%d %d\n",ans[i].first,ans[i].second);
    } 
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值