zoukankan      html  css  js  c++  java
  • [Atcoder Regular Contest 061] Tutorial

    Link:

    ARC061 传送门

    C:

    暴力$dfs$就好了

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    ll n,res=0;
    int dgt[15],cnt;
    
    void dfs(int dep,ll sum)
    {
        if(dep==cnt){res+=sum;return;}
        for(int i=dep+1;i<=cnt;i++)
        {
            ll t=0;
            for(int j=dep+1;j<=i;j++) 
                t=t*10+dgt[j];
            dfs(i,sum+t);
        }
    }
    
    int main()
    {
        scanf("%lld",&n);
        for(;n;n/=10) dgt[++cnt]=n%10;
        reverse(dgt+1,dgt+cnt+1);dfs(0,0);
        printf("%lld",res);
        return 0;
    }
    Problem C

     

    D:

    没有办法直接上暴力,但可以采取计算贡献的方式:

    每个有色点都对周围的9个正方形恰好有1点贡献

    将$9*k$个正方形用其左上角的坐标表示,排序后将相同的合并就是该正方形的个数了

    最后用总的减去个数为$[1,9]$的就是个数为0的个数了

    #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;
    P sqr[MAXN*10];
    ll sum=0,cnt[15];
    int n,m,k,x,y,tot;
    int dx[]={-2,-2,-2,-1,-1,-1,0,0,0};
    int dy[]={-2,-1,0,-2,-1,0,-2,-1,0};
    
    int main()
    {
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=k;i++)
        {
            scanf("%d%d",&x,&y);
            for(int j=0;j<9;j++)
            {
                int fx=x+dx[j],fy=y+dy[j];
                if(fx>0&&fy>0&&fx<=n-2&&fy<=m-2)
                    sqr[++tot]=P(fx,fy);
            }
        }
        
        sort(sqr+1,sqr+tot+1);
        int cur=1;
        for(int i=2;i<=tot;i++)
            if(sqr[i]==sqr[i-1]) cur++;
            else cnt[cur]++,cur=1;
        if(k) cnt[cur]++;//不要忘记对末尾的处理 
        
        for(int i=1;i<=9;i++) sum+=cnt[i];
        cnt[0]=1ll*(m-2)*(n-2)-sum;
        for(int i=0;i<10;i++) printf("%lld
    ",cnt[i]);
        return 0;
    }
    Problem D

    E:

    先来说说正解:拆点最短路

    在每个站点中,对于每一个其能转换到的公司都新设立一个站点,并建立一个总站

    也就是说,对于边$(u,v,c)$,建边$(u,u[c],1),(v,v[c],1),(u[c],v[c],0)$

    这样体现了是否转换公司的抉择,直接在新图上求最短路就好了

    但注意最后答案要除以2,毕竟这样建图每转换一次其实计算了2次1

    我的做法又是极为感性的

    在每个点都用一个$set$维护当前能达到最短距离时的末尾公司名,转移时贪心

    感觉没什么问题,但不知道为什么在距离相同时一定要先处理编号较大的节点?请各位神犇们指点啊……

    #include <bits/stdc++.h>
    
    using namespace std;
    #define X first
    #define Y second
    typedef pair<int,int> P;
    const int MAXN=1e5+10,INF=1<<27;
    int n,m,x,y,z,dist[MAXN];
    set<int> s[MAXN];
    vector<P> G[MAXN];
    //必须要用set,因为可能dist最小时有多种公司供选择 
    struct cmp
    {//一定要编号大的先处理(原因未知) 
        bool operator() (const P& a,const P& b)
        {return a.X!=b.X?a.X>b.X:a.Y<b.Y;}
    };
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            G[x].push_back(P(y,z));G[y].push_back(P(x,z));
        }
        
        priority_queue<P,vector<P>,cmp > q;
        for(int i=2;i<MAXN;i++) dist[i]=INF;
        dist[1]=0;q.push(P(0,1));
        while(!q.empty())
        {
            P t=q.top();q.pop();
            int u=t.Y,cost=t.X,tmp;
            if(cost>dist[u]) continue;
            for(int i=0;i<G[u].size();i++)
            {
                int v=G[u][i].X,col=G[u][i].Y;
                tmp=dist[u]+(!s[u].count(col));
                if(tmp==dist[v]) s[v].insert(col);
                else if(tmp<dist[v])
                {
                    s[v].clear();s[v].insert(col);
                    dist[v]=tmp,q.push(P(dist[v],v));
                }
            }
        }
        printf("%d",(dist[n]==INF)?-1:dist[n]);
        return 0;
    }
    Problem E

    F:

    设游戏结束前使用了$x$张$b$,$y$张$c$

    可以发现最终一共使用了$n+x+y$张卡片,且由于最后一张一定是$a$可以不用考虑

    因此可以比较容易的写出一下的式子:

    $res=sum_{p=0}^{m+k} C_{n−1+x+y}^{n-1}*3^{m+k−x−y}*sum_{0le xle m,0le yle k}[x+y=p]C_{p}^{x}$

    为了将计算的时间降到$O(n)$,我们可以用递推的方式优化$sum C_{p}^{x}$

    设$f(i)$表示$p=i$时该式的值,发现递推有三个阶段(假设$m<k$):

    1、$i<m$时$f(i)=sum_{j=0}^{i} C_i^j$

    2、$mle i<k$时$f(i)=sum_{j=0}^{m} C_i^j$

    3、$kle i$时$f(i)=sum_{j=i-k}^m C_i^j$

    将这些式子放到杨辉三角形上可以发现:

    1阶段时$f(i)=f(i-1)*2$(二项式系数和的基本结论)

    2阶段时$f(i)=f(i-1)*2-C_{i-1}^m$(减掉右边界的值)

    3阶段时$f(i)=f(i-1)*2-C_{i-1}^m-C_{i-1}^{i-1-k}$(减掉左右边界的值)

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    const int MAXN=(3e5+10)*3,MOD=1e9+7;
    ll res=0,cur=1;
    int n,m,k,fac[MAXN],inv[MAXN];
    
    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 C(int a,int b)
    {if(a<b||b<0) return 0;return 1ll*fac[a]*inv[b]%MOD*inv[a-b]%MOD;}
    
    int main()
    {
        scanf("%d%d%d",&n,&m,&k);
        fac[0]=1;
        for(int i=1;i<MAXN;i++)
            fac[i]=1ll*fac[i-1]*i%MOD;
        inv[MAXN-1]=quick_pow(fac[MAXN-1],MOD-2);
        for(int i=MAXN-2;i>=0;i--)
            inv[i]=1ll*inv[i+1]*(i+1)%MOD;
        
        for(int i=n;i<=n+m+k;i++)
            (res+=C(i-1,n-1)*cur%MOD*quick_pow(3,n+m+k-i)%MOD)%=MOD,
            cur=(2*cur-C(i-n,m)+MOD-C(i-n,i-n-k)+MOD)%MOD;
        printf("%lld",res);
        return 0;
    }
    Problem F

    优化方式涨姿势了

  • 相关阅读:
    Caused by: java.lang.ClassNotFoundException: org.hibernate.annotations.common.reflection.MetadataPro
    Caused by: java.lang.ClassNotFoundException: org.dom4j.DocumentException
    让你的C程序更有效率的10种方法
    c++效率浅析
    Caused by: java.lang.ClassNotFoundException: org.hibernate.engine.FilterDefinition
    Caused by: java.lang.ClassNotFoundException: javax.transaction.TransactionManager
    Caused by: java.lang.NoClassDefFoundError: org/hibernate/cfg/Configuration
    Caused by: java.lang.ClassNotFoundException: org.aspectj.weaver.reflect.ReflectionWorld$ReflectionWo
    Caused by: java.lang.ClassNotFoundException: org.jbpm.pvm.internal.processengine.SpringHelper
    Caused by: java.lang.ClassNotFoundException: org.aopalliance.intercept.MethodInterceptor
  • 原文地址:https://www.cnblogs.com/newera/p/9333925.html
Copyright © 2011-2022 走看看