zoukankan      html  css  js  c++  java
  • 2019 CCPC-Wannafly Winter Camp Day7(Div2, onsite)

    solve 6/11

    补题:

    A.迷宫

    Code:zz

    Thinking:zz kk

    把每个节点的深度都处理出来,同一深度的点的冲突度为 (x-1),x为同层次点数减一。

    然后冲突度不断下传(冲突度为3,则最多下传3层)

    最后答案就是最后一层的深度加上冲突度。

    #include<bits/stdc++.h> 
    #define CLR(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll;
    const int maxn=100010;
    int n,m;
    int a[maxn];
    bool vis[maxn];
    ll ans[maxn],No[maxn];
    struct egde{
        int to,Next;
    }e[maxn<<1];
    struct node{
        int u;
        ll time;
    };
    int head[maxn],tot;
    void init(){
        CLR(head,-1),tot=0;
        CLR(vis,0);
        CLR(ans,0);
        CLR(No,0);
    }
    void addv(int u,int v){
        e[++tot].to=v;
        e[tot].Next=head[u];
        head[u]=tot;
    }
    void bfs(){
        queue<node >q;
        q.push({1,0});
        vis[1] = true;
        ans[1] = 1;
        if(a[1])
        {
            No[1]++;
        }
        while(!q.empty())
        {
            node s=q.front();
            q.pop();
            int u=s.u;
            ll time=s.time;
            for(int i=head[u];i!=-1;i=e[i].Next)
            {
                int v=e[i].to;
                if(!vis[v])
                {
                    vis[v] = true;
                    q.push({v,time + 1});
                    ans[v] = time + 1 + 1;
                    if(a[v])
                    {
                        No[time + 1 + 1]++;
                    }
                }
            }
        }
    }
    int main(){
        while(cin>>n)
        {
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
            }
            init();
            for(int i=1;i<n;i++)
            {
                int u,v;
                scanf("%d%d",&u,&v);
                addv(u,v),addv(v,u);
            }
            bfs();
            ll aans = 0,mm = 0;
            for(int i = 1;i <= n;i++)
            {
                if(a[i])
                {
                    mm = max(mm,ans[i]);
                }
            }
            for(int i = 1;i <= n;i++)
            {
                if(mm == i)
                {
                    break;
                }
                No[i + 1] += max((ll)0,No[i] - 1);
            }
            printf("%lld
    ",No[mm] - 1 + mm - 1);
        }
    }
    View Code

    C.斐波那契数列

    Code:pai爷  zz  kk

    Thinking:pai爷  zz  kk

    根据式子观察得,这个式子就是斐波那契数列丢掉自己二进制的低位1的前缀和,也就是 fib n - lowbit(fib n),所以暴力打表把减掉的这部分打出来,找规律,然后矩阵快速幂求斐波那契数列前n项和,减一减。

    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<iostream>
    #include<map>
    using namespace std;
    typedef long long ll;
    const int p=998244353;
    const int mod = 998244353;
    ll f[1010],sum[1010],r;
    int t;
    void mul(ll f[3], ll a[3][3])
    {
        ll c[3];
        memset(c, 0, sizeof(c));
        for (int j = 0; j < 3; j++)
            for (int k = 0; k < 3; k++)
                c[j] = (c[j] + (long long)f[k] * a[k][j]%mod) % mod;
        memcpy(f, c, sizeof(c));
    }
    void mulself(ll a[3][3])
    {
        ll c[3][3];
        memset(c, 0, sizeof(c));
        for (int i = 0; i < 3; i++)
            for (int j = 0; j < 3; j++)
                for (int k = 0; k < 3; k++)
                    c[i][j] = (c[i][j] + (long long)a[i][k] * a[k][j]%mod) % mod;
        memcpy(a, c, sizeof(c));
    }
    ll quickm(ll n){//求第n项和 
        ll f[3] = { 1,1,1 };
            ll tep=n-1;
            ll a[3][3] = { {1,1,1},{1,0,0},{0,0,1} };
            for (; tep; tep >>= 1)
            {
                if (tep & 1) mul(f, a);
                mulself(a);
            }
            return f[2];
    }
    
    ll solve(ll x,int w)
    {
        if(x==0) return 0;
        if(x==1) return 1;
        if(x==2) return 2;
        if(x==3) return 4;
        if(x==4) return 5;
        if(x==5) return 6;
        if(x==6) return 14;
        for(int i=w;i>=1;i--)
        if(x>=1ll*6*f[i])
        {
            return (sum[i]+solve(x-6*f[i],i-1))%p;
        }
    }
    int main()
    {
        f[1]=1;sum[1]=14;
        for(int i=2;i<=61;i++) 
        {
            f[i]=f[i-1]*2;
            sum[i]=(sum[i-1]*2%p+f[i]*4%p)%p;
        }
        scanf("%d",&t);
        while(t--)
        {
            scanf("%lld",&r);
            ll ans=solve(r,61);
            //printf("%lld
    ",ans);
            printf("%lld
    ",(quickm(r)-ans+p)%p);
        }
    }
    View Code

    D 二次函数

    待补题 初中数学  

    E 线性探查法

    Code:kk

    Thinking:kk

    先把每个b[ i ]的余数求出来,余数等于i的说明没有冲突,不等于i的,假设偏移量为px,说明他的前px项都在他前面,所以就得到拓扑序,由于要字典序最小,所以用优先队列求拓扑序列。

    div2暴力建边即可,div1要线段树优化建边?待学习。

    #include<bits/stdc++.h> 
    #include<unordered_map>
    #define CLR(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll;
    const int maxn=1010;
    int n;
    ll a[maxn],b[maxn],m[maxn];
    int dg[maxn];
    
    struct egde{
        int to,Next;
    }e[maxn*maxn];
    int head[maxn],tot;
    void init(){
        CLR(head,-1),tot=0;
    }
    void addv(int u,int v){
        e[++tot].to=v;
        e[tot].Next=head[u];
        head[u]=tot;
    }
    struct node{
        int pos;
        ll val;
        friend bool operator <(const node &a,const node &b){
            return a.val>b.val;
        }
    };
    priority_queue<node >q;
    void Top(){
        int top=0;
        while(!q.empty()){
            node s=q.top();
            q.pop();
            a[++top]=s.val;
            for(int i=head[s.pos];i!=-1;i=e[i].Next)
            {
                int pos=e[i].to;
                dg[pos]--;
                if(dg[pos]==0)
                {
                    q.push({pos,b[pos]});
                }
            }
        }
    }
    int main(){
        while(cin>>n)
        {
            init();
            for(int i=0;i<n;i++)
            {
                scanf("%lld",&b[i]);
                m[i]=b[i]%n;
            }
            for(int i=0;i<n;i++)
            {
                if(m[i]==i)
                {
                    q.push({i,b[i]});
                }else{
                    int px=(i-m[i]+n)%n;
                    while(px>0)
                    {
                        addv((i-px+n)%n,i);
                        dg[i]++;
                        px--;
                    }
                }
            }
            Top();
            for(int i=1;i<=n;i++)
            {
                printf("%lld%c",a[i],(i<n)?' ':'
    ');
            }
        }
    }
    View Code

    F 逆序对!

    Code:pai爷

    Thinking:pai爷

    0(n*n)枚举每个数对有贡献的答案为不相同的最高位。

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<cstdio>
    #include<cstdlib>
    using namespace std;
    const int p=998244353;
    int n,m,x,f[1010][50];
    int sum,ans=0,chu,yu,a,b;
    int main()
    {
    //    freopen("1.txt","r",stdin);
    //    freopen("1.out","w",stdout);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&x);
            int l=0;
            while(x>0)
            {
                f[i][++l]=x%2;
                x/=2;
            }
            f[i][0]=l;
        }
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
            {
                int k;
                for(k=max(f[j][0],f[i][0]);k>=1;k--)
                    if(f[i][k]!=f[j][k]) break;
                    
                chu=m/(1<<(k-1));yu=m%(1<<(k-1));
                a=(chu-chu/2)*(1<<(k-1))-1;b=chu/2*(1<<(k-1));
                
                sum=yu+1;
                //printf("chu=%d yu=%d a=%d b=%d sum=%d k=%d
    ",chu,yu,a,b,sum,k); 
                if(chu%2==0) a+=sum,b=m-a;
                else b+=sum,a=m-b;
                if(f[i][k]==0) ans=(ans+b)%p;
                else ans=(ans+a)%p;
                ans=(ans+p)%p;
                //printf("%d
    ",ans);
            }
        printf("%d
    ",ans);
    }
    View Code

    G 抢红包机器人

    Code:zz

    Thinking:zz

    暴力枚举每个人是机器人的情况,再dfs查找出所有的机器人,选取机器人最少的情况。

    //#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;
    struct s
    {
        int k;
        int c[110];
    }z[110];
    vector<int>ve[110];
    int vis[110];
    unordered_map<int,int>mp[110];
    inline void dfs(int pos)
    {
        int si,i;
        si = ve[pos].size();
        for(i = 0;i < si;i++)
        {
            if(!vis[ve[pos][i]])
            {
                vis[ve[pos][i]] = 1;
                dfs(ve[pos][i]);
            }
        }
    }
    int main(void)
    {
        //ios::sync_with_stdio(false);
        int n,m,i,j,ans,mi,l;
        while(~scanf("%d %d",&n,&m))
        {
            for(i = 0;i <= n;i++)
            {
                ve[i].clear();
                mp[i].clear();
            }
            for(i = 0;i < m;i++)
            {
                scanf("%d",&z[i].k);
                for(j = 0;j < z[i].k;j++)
                {
                    scanf("%d",&z[i].c[j]);
                }
            }
            for(i = 0;i < m;i++)
            {
                for(j = z[i].k - 1;j >= 0;j--)
                {
                    for(l = j - 1;l >= 0;l--)
                    {
                        if(!mp[z[i].c[j]][z[i].c[l]])
                        {
                            mp[z[i].c[j]][z[i].c[l]] = 1;
                            ve[z[i].c[j]].push_back(z[i].c[l]);
                        }
                    }
                }
            }
            ans = 100000;
            for(i = 1;i <= n;i++)
            {
                memset(vis,0,sizeof(vis));
                vis[i] = 1;
                dfs(i);
                mi = 0;
                for(j = 1;j <= n;j++)
                {
                    if(vis[j])
                    {
                        mi++;
                    }
                }
                ans = min(ans,mi);
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    H 同构

    求补图,然后dp?待补

    J 强壮的排列

    Code:pai爷

    Thinking:pai爷

    暴力打表?待补


    赛后总结

    kk:今天是演员的一天,演队友演自己,开局A题就想错了思路,然后一直想错,两小时才把A题这水题做了,然后E题基本读完题意,稍微写写就得到正解了,结果建边数组少开了,re一发,给队友写个矩阵快速幂的板子,没注意数据范围,long long写成了int,tle一发。影帝影帝,以后演技要好一些,要注意细节。

    pai爷:模数复制粘贴错误找了一个小时的bug而且还wa了三发。找规律速度不够快。

    zz:这场比赛演技越来越好了,水题想了好多假算法,而且wa以后才发现。找规律的题贡献了一个表。

  • 相关阅读:
    CSV格式的文件与EXCEL文件的区别
    Arcgis 离线部署api 4.x的两种本地部署方法!
    IDEA版部署离线ArcGIS api for JavaScript
    java web中统一结果返回封装类JsonResult
    网络最大流dinic
    Luogu P3834 可持久化线段树2(主席树)
    LuoguP2824[HEOI2016/TJOI2016]排序
    2021.03.24模拟赛DP
    Luogu P3166数三角形
    乘法逆元
  • 原文地址:https://www.cnblogs.com/mountaink/p/10325107.html
Copyright © 2011-2022 走看看