zoukankan      html  css  js  c++  java
  • 20190718

    我是一如既往的弱。

    T1. 星际旅行

    很简单的一道乱搞题。

    将所有的边拆成两条,问题变成去掉两条边,使得原图存在一条欧拉路
    径。注意新图中所有点的度数均为偶数,只需按照去掉任意2个自环、去掉任
    意1个自环和任意一条边、去掉两条有公共顶点的边进行讨论即可。注意图不连
    通的判断方式,不是点不连通,而是边不连通。

    标准题解说是要把无向边拆为两条有向边,那么问题就转化为去掉两条边使得原图存在一条欧拉路径。

    要保证新图中所有点的度数都为偶数

    我们先考虑两种简单情况

    1. 删除任意两个自环 即 ans+=sum(be_back)*(sum(be_back)-1)/2;

    2. 删除任意一个自环和一条边 即 ans+=m(处自环外的路径 双向边单向注意*2)*sum(back);

    还有就是删除两条路径

    我们考虑怎样删除可以使得所有点的度数为偶 显然是删除连接着同一个点的两条边

    具体点呢?

    删除如图所示的两条即可

    用语言描述出来就是一条入边一条出边

    对于一个点方案数为 C(入度,1)*(C(出度,1) -1)

    记 入度或者出度为in 即in*(in-1) (式1)

    为什么要减一呢 因为你不能同时把原来的一条完整的无向边完全砍掉

    但是式1要除2 见 样例说明 (第七条路径与第一条不同)

    然后可以快乐的提交了

    题目很坑 要判边联通

    值得一提的是可以选择并查集 效率很高

    但是判断条件有点繁琐 一是存在两个大小>=2的集合 二是一个单独的点里有自环

    数据还是很棒的

    #include <vector>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define QAQ 100110
    #define re register
    #define ll long long
    #define max(a,b) ( (a) > (b) ) ? (a) : (b)
    #define min(a,b) ( (a) < (b) ) ? (a) : (b)
    #define fup(i,a,b) for(re int i=a;i<=b;++i)
    #define fdn(i,a,b) for(re int i=a;i>=b;--i)
    int fa[QAQ],in[QAQ],fu[QAQ];
    int n,m,be_back,sum;
    bool judge[QAQ];
    ll ans;
    inline ll read(){
        re ll x(0),f(1);re char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
        return x*f;
    }
    int find(re int x){
        return x==fa[x]?x:fa[x]=find(fa[x]);
    }
    inline void merge(re int x,re int y){
        x=find(x),y=find(y);
        fa[x]=y;
    }
    int main(){
        n=read(),m=read();
        fup(i,1,n)fa[i]=i;
        fup(i,1,m){
            re int x,y;
            x=read(),y=read();
            if(x==y){
                judge[x]=1;
                ++be_back;
            } else {
                merge(x,y);
                ++in[x];
                ++in[y];
                ++sum;
            }
        }
        fup(i,1,n)++fu[find(i)];
        bool flag=0;
        fup(i,1,n){
            if(fu[i]==1&&judge[i]){
                puts("0");
                return 0;
            }
            if(fu[i]>=2){
                if(!flag)flag=1;
                else {
                    puts("0");
                    return 0;
                }
            }
        }
        fup(i,1,n)ans+=1ll*(in[i]-1)*in[i]/2;
        ans+=1ll*be_back*(be_back-1)/2;
        ans+=1ll*be_back*sum;
        printf("%lld",ans);
    }
    SJQ

    T2.砍树

    不要二分!不要二分!!不要二分!!!

    其实并不难,比如soul大神A掉了

    问题等价于求一个最大的d,满足

    移项

    然后把d除过去

    (不会打 sigma 只能截题解QAQ)具体细节还是有点东西的

    右边就变成了 C/d 向下取整

    (联系数学函数 使 左边最大 小于 右边最小 则一定恒成立)

    左右都是单调递减(非严格)

    可以发现随着d的增大 左边的变化频率比较快 右边比较慢

    (蓝色为右,红色为左)

    为什么呢,其实很显然

    左边相当与先有误差后把误差加和 右边只有一次误差 左边会把误差放大

    可以手模几组例子

    如 3/2-> 2 5/2->3 7/2->4

    但 3/3-> 1 5/3->2 7/3->3

    而右边 (3+5+7+8888888)== (3+5+7+8888888)/3

    显然左边变化大

    下面定义的区间指的是d的取值范围

    对于每一个右边的区间 l->r 右边的值是不变的

    而左边在疯狂变化

    但是有单调性 即若式子在l可行那么整个 l->r 都可行

    同时 r 处不可行则整个区间都不行

    换言之,最优解在 r 处(如果中间交点处mid可行 那么r也可行 再换言之 若不行 则一定是在r出先开始)

    即暴力验证 r 处的 d 大小是否合适

    注意区间的范围就好了

     1 #include <vector>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <iostream>
     5 #include <algorithm>
     6 using namespace std;
     7 #define QAQ 100110
     8 #define re register
     9 #define ll long long
    10 #define max(a,b) ( (a) > (b) ) ? (a) : (b)
    11 #define min(a,b) ( (a) < (b) ) ? (a) : (b)
    12 #define fup(i,a,b) for(re int i=a;i<=b;++i)
    13 #define fdn(i,a,b) for(re int i=a;i>=b;--i)
    14 inline ll read(){
    15     re ll x(0),f(1);re char ch=getchar();
    16     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    17     while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    18     return x*f;
    19 }
    20 int a[QAQ];
    21 ll k,ans;
    22 int n;
    23 int main(){    
    24     ll sum=0,minn=888888888,maxx=0;
    25     n=read(),k=read();
    26     fup(i,1,n)a[i]=read(),sum+=a[i];
    27     sum+=k;
    28     ll d=0;
    29     while(1){
    30         if(sum/(d+1)==0)break;
    31         d=sum/(sum/(d+1));
    32         re ll can=0;
    33         fup(i,1,n){
    34             ll tot=a[i]/d;
    35             if(a[i]%d)++tot;
    36             can+=tot*d;
    37         }
    38         if(can<=sum)ans=d;
    39     }
    40     printf("%lld",ans);
    41 }
    SJQ

    T3.超级树

    先%一手DeepinC Orz TQL!

    题解太棒了!!!

    主要还是如何想到这种鬼畜的状态数组定义

    数言蔽之

    1.分析维度 考虑转移可能性

    2.分析时间,空间复杂度

    3.注意各个元素间的“公平”(很难描述,但是各个数据间确实有着微妙的联系,在以后的矩阵乘,dp中会多解释)

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #define Maxn 3050
     5 #define max(x,y) ((x)>(y)?(x):(y))
     6 #define Reg register
     7 using namespace std;
     8 long long sum,n,mod,dp[Maxn][Maxn];
     9 int main()
    10 {
    11     scanf("%lld%lld",&n,&mod);
    12     dp[1][1]=dp[1][0]=1;
    13     for(Reg int i=1;i<=n-1;++i)
    14     {
    15         for(Reg int j=0;j<=n-i+2;++j)
    16         {
    17             for(Reg int k=0;k<=n-i+2-j;++k)
    18             {
    19                 sum=(dp[i][j]*dp[i][k])%mod;
    20                 dp[i+1][j+k]=(dp[i+1][j+k]+sum)%mod;
    21                 //选j+k条路径 左和右分别选的贡献
    22                 dp[i+1][j+k+1]=(dp[i+1][j+k+1]+sum)%mod;
    23                 //选j+k+1条路径 左和右分别选+选根的贡献
    24                 dp[i+1][j+k]=(dp[i+1][j+k]+sum*2*(j+k))%mod;
    25                 //选j+k条路径 左(和右)分别选一条边(起点或终点)连到根的贡献
    26                 if(j+k-1>=0) dp[i+1][j+k-1]=(dp[i+1][j+k-1]+sum*j*k*2)%mod;
    27                 //选j+k-1条路径 左(右)选一条边到根在连右(左)的贡献
    28                 if(j+k-1>=0) dp[i+1][j+k-1]=(dp[i+1][j+k-1]+sum*(j*j-j+k*k-k))%mod;
    29                 //选j+k-1条路径 左(右)连根再连左(右)的贡献
    30             }
    31         }
    32     }
    33     printf("%lld",dp[n][1]%mod);
    34     return 0;
    35 }
    SJQ

    总体来说吧 我考的狗屁不是 不分析算法正确性(二分,最小生成树) 把题考虑太难(礼物,通讯,星际旅行)

    心态也很爆炸 中间一段时间根本什么都没码

    加油吧 lz爬也要爬到第一机房

    Fighting!

  • 相关阅读:
    js正则
    常用正则表达式
    JS
    Vue
    JS
    Cookie、Session和自定义分页
    ORM分组操作示例(与SQL语句的比较)以及基于对象和queryset的正反查询
    跨站请求伪造和csrf_token使用
    ORM之单表、多表操作
    Django中ORM介绍和字段及字段参数
  • 原文地址:https://www.cnblogs.com/bilibiliSmily/p/11209646.html
Copyright © 2011-2022 走看看