zoukankan      html  css  js  c++  java
  • [Codeforces #196] Tutorial

    Link:

    Codeforces #196 传送门

    A:

    枚举

    #include <bits/stdc++.h>
    
    using namespace std;
    #define X first
    #define Y second
    typedef long long ll;
    typedef pair<int,int> P;
    const int MAXN=1e5+10;
    int n,m,dat[MAXN],res=1<<30;
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++) scanf("%d",&dat[i]);
        sort(dat+1,dat+m+1);
        for(int i=1;i<=m-n+1;i++)
            res=min(res,dat[i+n-1]-dat[i]);
        printf("%d",res);
        return 0;
    }
    Problem A

    B:

    可以发现分母为$max(a*d,b*c)$,分子为$|a*d-b*c|$

    #include <bits/stdc++.h>
    
    using namespace std;
    #define X first
    #define Y second
    typedef long long ll;
    typedef pair<int,int> P;
    int a,b,c,d,ta,tb,tc,td,resx,resy;
    int GCD(int x,int y){return x%y==0?y:GCD(y,x%y);}
    
    int main()
    {
        scanf("%d%d%d%d",&a,&b,&c,&d);
        resx=abs(a*d-c*b),resy=max(a*d,c*b);
        int gcd=GCD(resx,resy);
        printf("%d/%d",resx/gcd,resy/gcd);
        return 0;
    }
    Problem B

    C:

    直接贪心,考虑将空格插入连续的序列中

    如果可以不翻倍自然答案就是$m$,否则应当尽可能在前面翻倍来减少增加的分数

    能推出翻倍$q$次后的分数为$(2^q-1)*2*k$,这样再加上剩余不翻倍的分数即可

    #include <bits/stdc++.h>
    
    using namespace std;
    #define X first
    #define Y second
    typedef long long ll;
    typedef pair<int,int> P;
    const ll MOD=1e9+9;
    ll n,m,k,res;
    ll quick_pow(ll a,ll b)
    {
        ll ret=1;
        for(;b;b>>=1,a=a*a%MOD)
            if(b&1) ret=ret*a%MOD;
        return ret;
    }
    
    int main()
    {
        scanf("%I64d%I64d%I64d",&n,&m,&k);
        if(!m||!n) return puts("0"),0;
        ll rst=n-m,num=n/k;
        if(rst>=num) res=m;
        else res=(quick_pow(2,num-rst)-1)*2*k%MOD+(m-(num-rst)*k%MOD);
        printf("%I64d",(res+MOD)%MOD);
        return 0;
    }
    Problem C

    D:

    官方题解:

    将原树转化成有根树,对于一个点的最远关键点分成两类:

    1、在该点的子树中,记最远距离为$MaxDown$

    2、在树上的其它部分,记最远距离为$MaxUp$

    对于1,明显可以$dfs$通过孩子节点来更新

    对于2,又要分为两类来更新:

    1、在其兄弟节点的子树中,即$MaxDown_{sibling}+2$

    2、不在父亲节点的子树中,即$MaxUp_{father}+1$

    其中注意用兄弟节点更新时要先记录最大/次大值来保证$O(1)$更新

    不过感觉我的方法更简单啊……

    先想想如何求一个点到树上任意点的最远距离

    明显是用数的直径来解决的经典问题,可用反证法证明最远点一定是直径的两端

    发现将任意点改为特定的关键点后该结论依然成立!

    因此只要找到关键点中最远的点对$(a,b)$,对于每个点$v$判断$dist(a,v),dist(b,v)le d$

    #include <bits/stdc++.h>
    
    using namespace std;
    #define X first
    #define Y second
    typedef long long ll;
    typedef pair<int,int> P;
    const int MAXN=1e5+10;
    int head[MAXN],tot;
    struct edge{int nxt,to;}e[MAXN<<2];
    int n,m,d,x,y,p[MAXN],rt1,rt2,d1[MAXN],d2[MAXN],res;
    
    void add(int from,int to)
    {e[++tot].nxt=head[from];e[tot].to=to;head[from]=tot;}
    void dfs(int x,int anc,int *d)
    {
        for(int i=head[x];i;i=e[i].nxt)
            if(e[i].to!=anc)
                d[e[i].to]=d[x]+1,dfs(e[i].to,x,d);
    }
    
    int main()
    {
        scanf("%d%d%d",&n,&m,&d);
        for(int i=1;i<=m;i++) scanf("%d",&p[i]);
        for(int i=1;i<n;i++)
            scanf("%d%d",&x,&y),add(x,y),add(y,x);
        
        d1[1]=0;dfs(1,0,d1);
        for(int i=1;i<=m;i++) if(d1[p[i]]>d1[rt1]) rt1=p[i];
        d1[rt1]=0;dfs(rt1,0,d1);
        for(int i=1;i<=m;i++) if(d1[p[i]]>d1[rt2]) rt2=p[i];
        d2[rt2]=0;dfs(rt2,0,d2);
        
        for(int i=1;i<=n;i++)
            if(d1[i]<=d&&d2[i]<=d) res++;
        printf("%d",res);
        return 0;
    }
    Problem D

    虽说第一种解法可能代码量稍大,但分类方法还是很实用的:

    将无根树转化成有根树后按照是否在该点的子树中分类

    其中兄弟节点对该点的贡献不要忘记统计!我一开始就漏掉了……

    E:

    发现最优解除了叶子节点和根外,其它节点必然都属于$a$

    考虑一个点向当前树插入,其要么接在某个节点后,要么重开一棵树

    由于$n$只有8,明显排序预处理后枚举各种组合就好了

    其中有一些技巧需要注意:

    1、采取从根到叶子的构造更加方便

    由于树根确定其叶子节点就已经确定,后面接点时就不用再考虑叶子节点的贡献了

    2、不要漏考虑最大点本身就是根的情况,这样答案会减少1

    #include <bits/stdc++.h>
    
    using namespace std;
    #define X first
    #define Y second
    typedef long long ll;
    typedef pair<int,int> P;
    ll n,dat[10],dvs[10],res=1ll<<60;
    
    void dfs(int k,int sum,int rt)
    {
        if(k==n+1)
        {res=min(res,sum+ll(rt>1));return;}
        if(dvs[k]>1) sum++;
        
        dfs(k+1,sum+dvs[k],rt+1);//单独成树 
        for(int i=1;i<k;i++)//连在之前的节点后 
            if(dat[i]%dat[k]==0)
                dat[i]/=dat[k],dfs(k+1,sum,rt),dat[i]*=dat[k];
    }
    
    int main()
    {
        scanf("%I64d",&n);
        for(int i=1;i<=n;i++) scanf("%I64d",&dat[i]);
        sort(dat+1,dat+n+1,greater<ll>());
        for(int i=1;i<=n;i++)
        {
            ll t=dat[i];
            for(int j=2;1ll*j*j<=dat[i];j++)
                while(t%j==0) t/=j,dvs[i]++;
            if(t>1) dvs[i]++; 
        }
        
        dfs(1,0,0);
        printf("%I64d",res);
        return 0;
    }
    Problem E
  • 相关阅读:
    curl.class.php方便使用
    php发送邮件
    php部分被弃用方法的代替方法
    正则表达式匹配
    php xml常用函数的集合及四种方法
    PHP5中使用PDO连接数据库的方法
    http协议的状态码
    MySQL数据库中的Date,DateTime和TimeStamp类型
    php中json_decode()和json_encode()的使用方法
    UIIabel自适配高度
  • 原文地址:https://www.cnblogs.com/newera/p/9522968.html
Copyright © 2011-2022 走看看