• HGOI 20190217 题解


    /*
        for me,开训第一天
    /beacuse 文化课太差被抓去补文化课了... 看一眼题 : AK局? 但是,Wa on test #10 in problem C 290! (就差那么一咪咪) 膜 _AK的_郝竟成 (id确实是这个) 说AK就AK了...
      他踩了STD 阿!
    (我)下午溜出去社会实践3h(with hjc)
    */

    今天的题目好像都是一眼题:

    Problem A  百万小小兵(Millian)

    问[1,n]和n不互质的数有几个?

    Solution: 在某同学在计算打表的时间的时候,默默的打开C++,写了n-Phi(n) 写完。

    # include <bits/stdc++.h>
    # define int long long
    using namespace std;
    const int N=1e6+10;
    bool pr[N];
    int prime[N];
    int cnt=0;
    int phi[N];
    void EouLaSha(int lim)
    {
        pr[0]=pr[1]=true;
        for (int i=2;i<=lim;i++) {
            if (!pr[i]) prime[cnt++]=i;
            for (int j=0;j<cnt&&i*prime[j]<=lim;j++) {
                pr[i*prime[j]]=true;
                if (i%prime[j]==0) break;
            }
        }
    }
    int Phi(int x) 
    {
        EouLaSha(1e6);
        int p=0,ph=x;
        for (;;){
            int nowprime=prime[p];
            if (nowprime>x||p==cnt) break;
            if (x%nowprime==0) ph=ph/nowprime*(nowprime-1);
            while (x%nowprime==0) x/=nowprime;
            p++;
        }
        if (x>1) ph=ph/x*(x-1);
        return ph;
    }
    signed main()
    {
        int n; cin>>n;
        cout<<n-Phi(n)<<'
    ';
        return 0;
    }

    Problem B 弹药分配(TNT)

    维护一个数组w[],有两个操作:

    1 a b k c : 把i∈[a,b]中,且i满足(i-a)%b==k的 w[i] += c

    2 p :  询问w[p]的值

    其中 n<=4e5,m<=4e5,答案不超过maxlongint

    对于所有数据 , k∈[1,10]

    Hint : 随机数据(真的!) 暴力(考试时A了,我把它卡了)

    Solution: 其实这个问题是分段线段树的问题,显然k的取值很小,首先mod k 有10种情况,mod k = t,t的取值有10种情况

    就开100棵树状数组,其中(i,j,k)表示一棵树状数组描述(k=i%j)这颗树状数组,然后树状数组维护差分前缀和(就是原数组w)

    考虑区间操作a,b,k,c 拆成 a-1单点模数是k余数是a%k 单点加上c,仅仅考虑对(i,k,a%k),只从i=a开始改变i,其他2参数不变。

    拆成b单点模数是k,余数是a%k 单点减去c,仅仅考虑(i,k,a%b)只从i=b开始改变i,其他两个参数不变。

    这是基于一个区间的变化只会在和这段区间中的点i∈[a,b]和a取模相等的才有贡献(这是显然的)这里相当于更新i∈[a,b]和a取模相等这一个树状数组。

    然后注意=0的越界情况,一直上不去(这里把倒过来建树状数组【后缀和】)

    # include <bits/stdc++.h>
    # define fp(i,s,t) for (int i=s;i<=t;i++)
    # define lowbit(x) (x&(-x))
    using namespace std;
    const int N=7e4+10;
    int c[N][11][11],a[N];
    //c[i][j][mod] 表示i%j=mod差分前缀和 
    int n,m;
    inline int read(int &x)
    {
        int X=0,w=0; char c=0;
        while(c<'0'||c>'9') {w|=c=='-';c=getchar();}
        while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();
        x=w?-X:X;
    }
    inline void write(int x)
    {
        if (x<0) {x=-x;putchar('-');}
        if (x>9) write(x/10);
        putchar('0'+x%10); 
    }
    void update(int x,int k,int mod,int opx)
    {
        if (x==0) return;
        for (;x;x-=lowbit(x)) {
            c[x][k][mod]+=opx;
        }
    }
    int query(int x,int k)
    {
        int ret=0;
        for (;x<=n;x+=lowbit(x)) {
            for (int j=1;j<=10;j++)
             ret+=c[x][j][k%j]; 
        }
        return ret;
    }
    int main()
    {
        read(n);
        fp(i,1,n) read(a[i]);
        read(m);
        while (m--) {
            int t; read(t);
            if (t==1) {
                int l,r,k,val;
                read(l); read(r); read(k); read(val);
                update(l-1,k,l%k,-val); update(r,k,l%k,val);
            } else {
                int l; read(l);
                write(query(l,l)+a[l]); putchar('
    ');
            }
        }
        return 0;
    }

     Problem C  家园重建

    给出n个点m条边的无向图, 求取边权最大的边构成的图,满足每个联通块都最多只有1个环。

    对于100%的数据 n<=300

    Solution: 首先没算好复杂度,点是n<=300,若是完全图边数就是n2条,想的应该不是O(n3)算法,至少是O(n2),导致一开始没出来,当然后面出来了

    我们考虑这样一个贪心,首先假设构造同样的图形(指形态一样即每个连通块的元素个数一样),显然是选每个联通块中的最大边权(Kruscal算法)

    然后考虑吧可以多出1个环,那么就用并查集维护,如果这两个点u,v之间有一条边了,而且是剩下边里面最大的,我判断u,v可不可以加,如果可以的话就加入,不行的话就下一条边,至加完。

    首先如果u所在连通块和v所在连通块有环了,那么不可能(超过1个环的限制)

    其次如果u和v本身联通,但无环那么可以连边(标记父亲有环)

    如果u和v本身不连通,且无环,那么连边、合并(不标记父亲属于最大生成树)

    每次合并的时候注意把没环的合到有环的上面就行(判断有无环只要看父亲就行了!)

    复杂度O(n2 log n2)

    # include <bits/stdc++.h>
    # define int long long
    # define fp(i,s,t) for (int i=s;i<=t;i++)
    using namespace std;
    const int N=310;
    struct rec{int x,y,w;}e[N*N];
    int f[N],n,m,ans;
    bool cir[N];
    bool cmp(rec a, rec b){return a.w>b.w;}
    inline int read(int &x)
    {
        int X=0,w=0; char c=0;
        while(c<'0'||c>'9') {w|=c=='-';c=getchar();}
        while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();
        x=w?-X:X;
    }
    int father(int x)
    {
        if (x==f[x]) return x;
        return f[x]=father(f[x]);
    }
    signed main()
    {
        read(n);read(m);    
        fp(i,1,m) read(e[i].x),read(e[i].y),read(e[i].w),e[i].x++,e[i].y++;
        sort(e+1,e+1+m,cmp);
        fp(i,1,n) f[i]=i;
        fp(i,1,m) {
            int u=e[i].x,v=e[i].y,w=e[i].w;
            int fx=father(u),fy=father(v);
            if (fx!=fy) {
                if (cir[fx]&&cir[fy]) continue; 
                ans+=w;
                if (cir[fx]) f[fy]=fx;
                else f[fx]=fy; 
            } else {
                if (cir[fx]) continue;
                ans+=e[i].w;
                cir[fx]=true;
            }
        }
        cout<<ans<<'
    ';
        return 0;
    }
  • 相关阅读:
    查看CLOUD系统级IIS日志
    采购订单设置采购部门为缺省值
    单据头数据复制到单据体
    CLOUD设置过滤方案不共享
    BZOJ 4773: 负环 倍增Floyd
    LOJ #539. 「LibreOJ NOIP Round #1」旅游路线 倍增floyd + 思维
    BZOJ 4821: [Sdoi2017]相关分析 线段树 + 卡精
    一些常用公式/技巧
    BZOJ 4517: [Sdoi2016]排列计数 错排 + 组合
    BZOJ 3162: 独钓寒江雪 树的同构 + 组合 + 计数
  • 原文地址:https://www.cnblogs.com/ljc20020730/p/10392507.html
Copyright © 2020-2023  润新知