• 2019 CCPC-Wannafly Winter Camp Day3(Div2, onsite)


    solve 4/11

    补题:5/11

    A 二十四点*

    Code:pai爷  zz

    Thinking :pai爷

    打表找规律,1张牌 10个不可能的 2张牌有 43 种不可能的 3张牌 有74 种不可能的 4 张牌有 5 种不可能的

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #include<cstdio>
    #include<algorithm>
    #include<string>
    #include<map>
    #include<queue>
    #include<vector>
    #include<stack>
    #define ll long long
    #define maxn 401000
    int  main()
    {
        int n,a[20];
        while(scanf("%d",&n)!=EOF)
        {
            for(int i=1;i<=n;i++) scanf("%d",&a[i]);
            if(n==6) printf("32
    ");
            else  printf("891
    ");
        }
    }
    View Code

    B 集合

    分类加二分

    留坑

    E 精简改良

    生成树状压dp  dp[ s ] [ i ] 表示s状态(节点组成)下,以i为根的树的信息。

    留坑

    F 小清新数论

    Code:pai爷

    Thinking:pai爷

    莫比乌斯反演简单题

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #include<cstdio>
    #include<algorithm>
    #include<string>
    #include<map>
    #include<queue>
    #include<vector>
    #include<stack>
    #define ll long long
    #define maxn 401000
    const int P=998244353;
    using namespace std;
    inline int rd()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int tot;
    int a,b,c,d,k,n,l;
    int sum[10000005],mu[10000005],pri[10000005],X[10000005],Y[10000005];
    bool mark[10000005];
    void getmu()
    {
        mu[1]=1;
        for(int i=2;i<=10000000;i++)
        {
            if(!mark[i]){mu[i]=-1;pri[++tot]=i;}
            for(int j=1;j<=tot&&i*pri[j]<=10000000;j++)
            {
                mark[i*pri[j]]=1;
                if(i%pri[j]==0) { mu[i*pri[j]]=0;break; }
                else mu[i*pri[j]]=-mu[i];
            }
        }
        for(int i=1;i<=10000000;i++) sum[i]=sum[i-1]+mu[i];    
    }
    int cal(int n,int m)
    {
        if(n>m) swap(n,m);
        int ans=0,pos;
        for(int i=1;i<=n;i=pos+1)
        {
            pos=min(n/(n/i),m/(m/i));
            ans=(ans+1ll*(sum[pos]-sum[i-1])*(n/i)*(m/i))%P;
        }
        return ans;
    }
    int main()
    {
        getmu();
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
           if(mu[i]!=0)
           {
                X[++l]=i;
                Y[l]=mu[i];
           }
        ll su=0;
        for(int i=1;i<=l;i++)
        {
            a=1;b=n;c=1;d=n;k=X[i];
            a--;c--;
            a/=k;b/=k;c/=k;d/=k;
            ll ans=cal(b,d);
            if(Y[i]==1) su=(su+ans+P)% P;
            else su=(su-ans+P)%P;
        }
        printf("%lld
    ",su);
    }
    View Code

    G 排列

    Code:zz

    Thinking:zz

    原序列p的前缀最小值数组肯定是非递增的,如果原序列p是递减的,那么q是递减的,否则,如果出现“1,2,3”这种排列,它的前缀最小数组是“1,1,1”,后一位是小于等于前一位的,q是“1,2,3”,这样q的这种部分就会出现递增的情况。因此,从前往后遍历整个q数组,如果递减,那么对应位置的p排列的地方就应该尽量小;如果遇到递增的地方,那么那片地方的数对应的p排列的地方应该尽量大,并且为了字典序最小,p排列的那片地方应该递增。

    //#pragma comment(linker, "/STACK:102400000,102400000")
    #include<iostream>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<string>
    #include<math.h>
    #include<cmath>
    #include<time.h>
    #include<map>
    #include<set>
    #include<vector>
    #include<queue>
    #include<algorithm>
    #include<numeric>
    #include<stack>
    #include<bitset>
    #include<unordered_map>
    const int maxn = 0x3f3f3f3f;
    const double EI = 2.71828182845904523536028747135266249775724709369995957496696762772407663035354594571382178525166427;
    const double PI = 3.141592653589793238462643383279;
    using namespace std;
    int c[100010],ans[100010];
    int main(void)
    {
        //ios::sync_with_stdio(false);
        int n,i,z1,z2,pos1,pos2,j;
        while(~scanf("%d",&n))
        {
            for(i = 1;i <= n;i++)
            {
                scanf("%d",c + i);
            }
            z1 = 1;
            z2 = n;
            for(i = 1;i <= n;)
            {
                if(c[i] == z2)
                {
                    //printf("  %d %d %d
    ",i,c[i],z1);
                    ans[c[i]] = z1++;
                    //printf("%d %d %d
    ",ans[c[i]],c[i],ans[5]);
                    i++;
                }
                else
                {
                    ans[c[i]] = z1++;
                    i++;
                    pos1 = i;
                    for(;i <= n;i++)
                    {
                        if(c[i] == c[i - 1] + 1)
                        {
                            ans[c[i]] = z2--;
                        }
                        else
                        {
                            break;
                        }
                    }
                    
                    pos2 = i - 1;
                //    printf("* %d %d
    ",pos1,pos2);
                    for(j = pos1;pos1 < pos2 && j <= pos1 + (pos2 - pos1) / 2;j++)
                    {
                //        printf("1111 %d %d %d %d %d %d
    ",c[j],c[pos2 - j + pos1],ans[c[j]],c[pos2 - j + pos1],j,pos2 - j + pos1);
                        int tmp = ans[c[j]];
                        ans[c[j]] = ans[c[pos2 - j + pos1]];
                        ans[c[pos2 - j + pos1]] = tmp;
                //        printf("2222 %d %d %d %d
    ",c[j],c[pos2 - j + pos1],ans[c[j]],c[pos2 - j + pos1]);
                    }
                }
            }
            //printf("   %d
    ",ans[5]);
            for(i = 1;i <= n;i++)
            {
                printf("%d",ans[i]);
                if(i != n)
                {
                    printf(" ");
                }
            }
            printf("
    ");
        }
        return 0;
    }
    View Code

    H 涂鸦*

    Code:pai爷

    Thinking:pai爷

    差分约束+逆元

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #include<cstdio>
    #include<algorithm>
    #include<string>
    #include<map>
    #include<queue>
    #include<vector>
    #include<stack>
    #define ll long long
    #define maxn 401000
    const int p=998244353;
    int f[1010][1010],ans[1010][1010],z[1010][1010];
    int n,m,q,l,r,a,b,c,d,an=0;
    ll qpow(ll a,ll b,ll p)
    {
        ll ret=1;a%=p;
        while(b)
        {
            if(b&1) ret=ret*a%p;
            b/=2;a=a*a%p;
        }
        return ret;
    }
    void init()
    {
        for(int i=1;i<=1000;i++)
        {
           f[i][0]=i*(i+1)/2;
           for(int j=1;j<=i;j++)
                  f[i][j]=(i-j+1)*j;
        }
    }
    int  main()
    {
       init();
       scanf("%d%d%d",&n,&m,&q);
       for(int i=1;i<=n;i++)
       {
            scanf("%d%d",&l,&r);
            for(int j=l;j<=r;j++) 
            {
                int sp=r-l+1;
                ans[i][j]=1ll*f[sp][j-l+1]*qpow(f[sp][0],p-2,p)%p; 
         } 
       }
       for(int i=1;i<=q;i++)
       {
               scanf("%d%d%d%d",&a,&b,&c,&d);
               for(int j=a;j<=c;j++)
               {
                   z[j][b]++;
                   z[j][d+1]--;
            }
       }
       for(int i=1;i<=n;i++)
          for(int j=1;j<=m;j++) z[i][j]+=z[i][j-1];
       for(int i=1;i<=n;i++)
          for(int j=1;j<=m;j++)
              if(z[i][j]==0)
              {
                  an=(an+ans[i][j])%p;
              }
        printf("%d
    ",an);
    }
    View Code

    I 石头剪刀布

    带权并查集 (树好像也可以做?)

    补题:kk

    按照题意描述,所有y挑战x的关系最后会形成一棵树的结构,n个人的总方案数是 3n 种,假设一个人被挑战(主场作战)a次,挑战别人(客场)b次,那么这个人存活到最后的方案数就是3n*(2/3)a*(1/3)b

    也就是我们知道这个a和b就可以得到答案了,那要怎么维护呢。

    这里用到并查集(jls niub!)

     我们用w表示一个节点总共比赛的场次数,v表示主场作战的场次数,如果我们现在把y这个集合并向x这个集合(y挑战x),那么对于XW和Xv肯定都加一,而Yw也加一,如果我们接下来能很好的合并这些信息,那我们就AC了。

    这里想了很久,才想明白要怎么做。我们先考虑暴力一点的并查集,就是不路径压缩,那每个节点就可以向上把所有父节点的信息全部加起来,就是我们最后要的某一个节点的W和V了,但是这样做会TLE,因为我们没有路径压缩,查找的时间复杂度很可能退化成O(n),但是我们又不能路径压缩(为什么不行,大家可以尝试一下,反正我自闭了一下午加一晚上)。

    普通的带权并查集我们用的都是路径压缩版本的,而这里我们要按秩合并,这样查找的时间复杂度就可以被优化到O(logn)。

    曾经我一直以为带权并查集的路径压缩和按秩合并是同一个东西,这道题真的学到了。。

    #include<bits/stdc++.h> 
    #define CLR(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll;
    const int maxn=200010;
    int fa[maxn],Rank[maxn];
    ll w[maxn],v[maxn];
    int n,m;
    int op,x,y;
    ll p= 998244353;
    struct node{
        int fx;
        ll w,v;
    };
    ll qpow(ll a,ll b){
        a%=p;
        ll res=1;
        while(b>0)
        {
            if(b&1){
                res*=a;
                res%=p;
            }
            b>>=1;
            a=a*a%p;
        }
        return res;
    }
    void init(){
        for(int i=1;i<=n;i++){
            fa[i]=i;
            w[i]=0;
            v[i]=0;
            Rank[i]=0;
        }
    }
    node find(int x){
        if(x==fa[x]) return {fa[x],w[x],v[x]};
        
        int tep=fa[x];
        node e;
        e.w=w[x],e.v=v[x];
        while(tep!=fa[tep]){
            e.w+=w[tep],e.v+=v[tep];
            tep=fa[tep];
        }
        e.fx=tep;
        e.v+=v[tep],e.w+=w[tep];
        return e;
    }
    
    void baba(int x,int y){
        node ex=find(x),ey=find(y);
        if(ex.fx!=ey.fx){
            w[ex.fx]+=1;
            v[ex.fx]+=1;
            w[ey.fx]+=1;
            v[ey.fx]+=0;
            if(Rank[ex.fx]>=Rank[ey.fx])
            {
                w[ey.fx]-=w[ex.fx];
                v[ey.fx]-=v[ex.fx];
                fa[ey.fx]=ex.fx;
                Rank[ex.fx]++;
            }else{
                w[ex.fx]-=w[ey.fx];
                v[ex.fx]-=v[ey.fx];
                fa[ex.fx]=ey.fx;
                Rank[ey.fx]++;
            }
    
        }
    }
    int main(){
        while(cin>>n>>m)
        {
            init();
            ll res=qpow(3,n);
            ll ans;
            while(m--)
            {
                scanf("%d%d",&op,&x);
                if(op==1){
                    scanf("%d",&y);
                    baba(x,y);
                }else{
                    node ex=find(x);
                    ll a=ex.v;
                    ll b=ex.w-ex.v;
                    ans=res*qpow(qpow(3,b),p-2)%p*qpow(2,a)%p*qpow(qpow(3, a),p-2)%p;
                    printf("%lld
    ",ans);
                }
            }
        }
    }
    View Code

    训练总结:

    kk:今日贼菜,0贡献,键盘都没摸一下,石头剪刀布想到用带权并查集表示关系,但不会算情况数是多少,然后就换想法了?自己会的东西还是太少了,pai爷牛逼,zz牛逼!

    pai爷:今天24点题目读错背锅了,之后知道是这样的就打表找不可能的情况,花了很多时间。整个人状态不是很好,做题缺少了节奏。最后一小时没有什么想法。

    zz:今天做了一道签到题以后就开始跟着金老师研究24点,但是除了手写打表没什么贡献,后来又想了石头剪刀布和几何题,都没什么想法,最后也没做出来。

  • 相关阅读:
    【2】网站搭建:数据库选型
    【1】网站搭建:模型设计
    输入法评价
    站立会议个人博客六
    站立会议个人博客五
    站立会议个人博客四
    站立会议个人博客三
    第十一周学习进度表
    站立会议个人博客二
    典型用户和用户场景描述。
  • 原文地址:https://www.cnblogs.com/mountaink/p/10306362.html
Copyright © 2020-2023  润新知