zoukankan      html  css  js  c++  java
  • 20210713考试-2021noip13

    这位巨佬的博客还是比我好多了


     T1 工业题

    考场:

    暴力挺香的,不想正解了。

    题解:

    $f(i,j)$ 只会得到 $f(i-1,j)$ 和 $f(i,j-1)$ 的贡献。每向右一步乘 $a$ ,向下一步乘 $b$ 。左侧竖点有$inom{n+m-1-i}{m-1}$种走法,上侧横店有$inom{n+m-1-i}{n-1}$种走法.

    预处理阶乘和阶乘逆元以及 $a,b$ 的幂次方即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=11000000,mod=998244353;
    long long a,b,n,m,inc[N],jc[N],am[N],bm[N],fheng[N],fshu[N],ans;
    long long quick_pow(long long x,long long y)
    {
        long long res=1;
        while(y)
        {
            if(y&1)
            {
                res=res*x%mod;
            }
            y>>=1;
            x=x*x%mod;
        }
        return res;
    }
    long long C(int n,int m)
    {
        return jc[n]*inc[m]%mod*inc[n-m]%mod;
    }
    int main()
    {
        scanf("%lld%lld%lld%lld",&n,&m,&a,&b);
        a%=mod;b%=mod;
        am[0]=bm[0]=jc[0]=inc[0]=1;
        for(int i=1;i<=n+m;i++)
        {
            jc[i]=jc[i-1]*i%mod;
            am[i]=am[i-1]*a%mod;
            bm[i]=bm[i-1]*b%mod;
        }
        inc[n+m]=quick_pow(jc[n+m],mod-2);
        for(int i=n+m-1;i>=1;i--)
        {
            inc[i]=inc[i+1]*(i+1)%mod;
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&fheng[i]);fheng[i]%=mod;
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%lld",&fshu[i]);fshu[i]%=mod;
        }
        for(int i=1;i<=n;i++)
        {
            ans+=fheng[i]*C(n+m-1-i,m-1)%mod*am[m]%mod*bm[n-i]%mod;
            ans%=mod;
        }
        for(int i=1;i<=m;i++)
        {
            ans+=fshu[i]*C(n+m-1-i,n-1)%mod*am[m-i]%mod*bm[n]%mod;
            ans%=mod;
        }
        printf("%lld
    ",ans);
        return 0;
    }

     T2 卡常题

     考场:

    灵光乍现,发现如果把y部点删去,只剩下每个y点所连的边,题目所给的图就变成了一棵基环树。

    原因:x,y部点都只有 $n$ 个如果把y点变成 $n$ 条边,那么由于题目保证联通且无重边,$n-1$ 的边构成一棵树,剩下的一条边随机连接,构成环。

    问题就转化成了,在一棵基环树上,选择一个点的代价为该点所连边的权值和,选择的点可以“看守”所连的边,求所有边被看守的最小代价。

    题解:

    考场上我按照轮流断掉环中的每一条边,每次跑 $O(n)$ 树形DP来做的,即使看到能被卡成 $O(n^2)$ 的环形数据,依然执迷不悟。

    事实上断哪一条边对答案完全没有影响,因为DP所求的和所需的完全没有变。 而且如果随机选一个点作为树根,难以保证断掉的边两侧的点一定选择了之一。

    所以钦定其中一个点为根,跑两次DP。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1100000,M=N<<1;
    int n,aa,bb,cnt=1,head[N],circle[N<<1],num,c1,c2,du[N],e,f[2][N][2],ans=0x7fffffff,sam[N];
    bool vis[N],used[N];
    inline int read()
    {
        int s=0,w=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
        while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
        return s*w;
    }
    inline int _min(int a,int b)
    {
        return a<b?a:b;
    }
    struct bian
    {
        int nxt,to,w[2];
    }b[M];
    void add(int from,int to,bool g)
    {
        du[from]++;du[to]++;
        b[++cnt].w[g]=aa;
        b[cnt].w[g^1]=bb;
        b[cnt].nxt=head[from];
        b[cnt].to=to;
        head[from]=cnt;
    }
    void findcir1(int u,int fa)
    {
        vis[u]=1; 
        for(int i=head[u],v;i;i=b[i].nxt)
        {
            v=b[i].to;
            if(v==fa) continue;
            else if(vis[v])
            {
                c1=u,c2=v;e=i;
                return;
            }
            else
            {
                findcir1(v,u);
            }
        }
    }
    bool findcir2(int u)
    {
        bool ok=0;
        for(int i=head[u],v;i;i=b[i].nxt)
        {
            if(used[i])
                continue;
            v=b[i].to;
            circle[++num]=i;
            circle[++num]=i^1;
            used[i]=used[i^1]=1;
            if(du[v]==2)
            {
                circle[num--]=0;
                circle[num--]=0;
                continue;
            }
            if(v==c1)
            {
                ok=1;return ok;
            }
            ok=findcir2(v);
            if(!ok)
            {
                circle[num--]=0;
                circle[num--]=0;
                continue;
            }
            else
                return ok;
        }
        return ok;
    }
    void DP(int x,int fa,int o)
    {
        int sum=0;
        f[o][x][0]=0;
        f[o][x][1]=sam[x];
        for(int i=head[x];i;i=b[i].nxt)
        {
            if(i==e||(i^1)==e||b[i].to==fa)continue;
            DP(b[i].to,x,o);
            sum+=min(f[o][b[i].to][0],f[o][b[i].to][1]);
            f[o][x][0]+=f[o][b[i].to][1];
        }
        f[o][x][1]+=sum;
    }
    int main()
    {
        n=read();aa=read();bb=read();
        for(int i=1,u,v;i<=n;i++)
        {
            u=read();v=read();
            add(u,v,0);
            add(v,u,1);
            sam[u]+=aa;
            sam[v]+=bb;
        }
        findcir1(1,0);
        findcir2(c1);
        memset(used,0,sizeof(used));
        DP(c1,0,0);
        DP(c2,0,1);
        printf("%d
    ",_min(f[0][c1][1],f[1][c2][1]));
        return 0;
    }

    T3 玄学题 

     

    $egin{align}ans=sum_{i=1}^{n}(-1)^{sum_{j=1}^{m}d(i*j)}\ans=sum_{i=1}^{n}(-1)^{sum_{j=1}^{m}d(i*j) mod 2}end{align}$

    因为奇+奇=偶,奇+偶=偶,偶+偶=偶,

    所以,只有 $d(i*j)$ 为奇数,才对和式整体有贡献。

    这时 $i*j$ 为完全平方数,假设i=p*q*q,那么 $j$ 是 $p*r*r$。

    对于每一个 $i$,有$sqrt{lfloor frac{m}{p} floor}$ 个j对和式产生了贡献。

    (只有能使 $-1$ 的幂增减 $1$ 的才算对和式产生了贡献)

    #include<bits/stdc++.h>
    using namespace std;
    inline long long read()
    {
        long long s=0,w=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
        while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
        return s*w;
    }
    const int N=11000000;
    long long n,m,ans,p[N];
    bool flag[N];
    int main()
    {
        n=read();m=read();
        scanf("%lld%lld",&n,&m);
        for(int i=1;i*i<=n;i++)
        {
            for(int j=1;j*i*i<=n;j++)
            {
                p[i*i*j]=j;
            }
            flag[i*i]=1;
        }
        int s=sqrt(m);
        for(int i=1;i<=n;i++)
        {
            if(flag[i])
            {
                if(s&1)
                    ans--;
                else
                    ans++;    
            }
            else
            {
                int x=sqrt(m/p[i]);
                if(x&1)
                    ans--;
                else ans++;    
            }
        }
        printf("%lld
    ",ans)
        ;
        return 0; 
    } 

     这两场都好拉跨啊QWQ每一次就离正解一步之遥。

  • 相关阅读:
    selenium重定项
    软件测试
    Flask中的session机制
    pythony--运算符
    笨办法学Python记录--习题18 变量 函数 help的由来;if语句,循环和列表,冒泡排序,判断输入字符串的方法
    笨办法学Python记录--习题15-17 开始读写文件啦
    笨办法学Python记录--习题12-14 主要是pydoc用法,raw_input,argv
    笨办法学Python记录--习题1-11
    随意从Android端抓取一些数据包看到的协议
    Git Learning Part II
  • 原文地址:https://www.cnblogs.com/HKHbest/p/15006861.html
Copyright © 2011-2022 走看看