zoukankan      html  css  js  c++  java
  • 牛客练习赛60 A—F题解(缺E题)

    本蒟蒻这次只过了三题 赛后学习了一下出题人巨佬的标码(码风比我好多了 贴的代码有些是仿出题人)
    现在将自己的理解写下来与大家分享

    A
    这个题一分析就是每个数字都会与所有数字&一下 (a&a=a)
    &字操作是二进制同位都为一才为一 这时解法就变成统计每个二进制位上1的次数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const ll maxn = 1e5;
    const ll maxm = 30;
    ll res;
    ll arr[maxn + 5], n, cnt[maxm + 5];
     
    int main()
    {
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i)scanf("%d", &arr[i]);
        for (int i = 1; i <= n; ++i)
            for (int j = 0; j < 30; ++j)
                if (arr[i] & (1 << j))cnt[j] += 1;///各位上1的个数
        for (int i = 0; i < 30; ++i)res +=  cnt[i] * cnt[i] * (1 << i);
        printf("%lld ", res);
        return 0;
    }

    B
    简单的n2枚举 分析一下可以知道每条边都用了n-2次

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    ll n,ans;
    ll mod=998244353;
    struct P
    {
        ll x,y;
    }a[110];
    ll len(P m,P n)
    {
        return abs(m.x-n.x)+abs(m.y-n.y);
    }
    int main()
    {
        scanf("%lld",&n);
        for(int i=1;i<=n;++i)scanf("%lld%lld",&a[i].x,&a[i].y);
        for(int i=1;i<=n;++i)
        {
            for(int j=i+1;j<=n;++j)
            {
               ans+=(len(a[i],a[j])*(n-2))%mod;
            }
        }
        cout<<ans%mod<<endl;
        return 0;
    }

    C
    这是一个比较基础的dp方程的进阶 从n个物品中选k个
    dp[i][j]=dp[i-1][j]+dp[i-1][j-1]
    i表示到第几个字符了 j是用了几个字符
    dp[i-1][j]是不用这个新加的 dp[i-1][j-1]是用这个新加的
    这题的关键点是我们这样计算重复了多少字符(本质不同的解释)
    其实仔细一想 我们重复计算就是相当于把 输出前面出现的那个符号在那里又多算了一次
    多了哪一部分 这个重复符号上次出现的位置的dp值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
     
    const ll maxn = 1000;
    const ll mod = 1e9 + 7;
     
    ll dp[maxn + 5][maxn + 5];
     
    ll n, k, pre[maxn + 5];///pre记录上次同一个字符的出现位置
    char s[maxn + 5];
     
    int main()
    {
        scanf("%d %d", &n, &k);
        scanf("%s", s + 1);
        dp[0][0] = 1;///n中选0个为1种情况
        for (int i = 1; i <= n; ++i) {
            dp[i][0] = 1;
            for (int j = 1; j <= i; ++j) {
                dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1];
                if (pre[s[i] - 'a'])dp[i][j] -= dp[pre[s[i] - 'a'] - 1][j - 1];
                dp[i][j] %= mod;
            }
            pre[s[i] - 'a'] = i;
        }
        ll res = dp[n][k];
        if (res < 0)res += mod;
        printf("%lld ", res);
        return 0;
    }

    D
    这题由于蒟蒻(我)追求梦想用n2枚举过了 但赛后还是写了一下正解方程(n枚举应该可以过)
    写这题你需要一个 扩展欧几里得模板(能判断是否有整数解) 然后枚举一个数就把题目变成了一个模板题了 前面是n2枚举 后面大概是正解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    ll a,b,c,k,minl;
    int main()
    {
        cin>>a>>b>>c>>k;
        minl=min(a,min(b,c));
        ll s=k/minl;
        for(int i=1;i<=s;++i)
        {
            for(int j=1;j<=s;++j)
            {
                ll z1=k-a*i-b*j;
                ll z2=k-b*i-c*j;
                ll z3=k-a*i-c*j;
                if(z1%c==0){cout<<i<<" "<<j<<" "<<z1/c;return 0;}
                if(z2%a==0){cout<<z2/a<<" "<<i<<" "<<j;return 0;}
                if(z3%b==0){cout<<i<<" "<<z3/b<<" "<<j;return 0;}
            }
        }
        return 0;
    }
     
    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    ll a,b,c,k;
    void exgcd(ll a,ll b,ll&x,ll&y)
    {
        if(b==0)
        {
            x=1;
            y=0;
            return;
        }
        exgcd(b,a%b,x,y);
        ll t=x;
        x=y;
        y=t-(a/b)*y;
    }
     
    ll gcd(ll a,ll b){
        return b==0?a:gcd(b,a%b);
    }
     
    int main()
    {
        scanf("%lld%lld%lld%lld",&a,&b,&c,&k);
        for(ll i=0;i<=k/c;i++){
            ll d=k-i*c;
            ll x,y;
            exgcd(a,b,x,y);
            ll e=gcd(a,b);
            if(d%e!=0continue;///有无解
            ll n=d/e;
            ll m=b/e;
            x*=n;y*=n;
            x=(x%m+m)%m;
            y=(d-x*a)/b;///有无整数解
            if(x>=0&&y>=0){
                printf("%lld %lld %lld",x,y,i);
                return 0;
            }
        }
        return 0;
     }

    F
    这题作为正在学习计算几何的蒟蒻(我) 那肯定是要学习的
    做这题的关键是要注意画图才能理解 代码里大部分有注释

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    #include<bits/stdc++.h>
    #define lowbit(x) x&(-x)
    #define ll long long
    using namespace std;
    typedef pair<int,int> pii;
     
    const int maxn=1e5+7;
    const int pi=acos(-1.0);
    const double eps=1e-9;
     
    int read()///快读
    {
        int x=0,f=1;char s=getchar();
        for( ;!isdigit(s);s=='-' && (f=-1),s=getchar());
        for( ;isdigit(s);x=x*10+s-48,s=getchar());
        return x*f;
    }
     
    struct point
    {
        int x,y,tag;
        point( ) { x=y=tag=0; }
        point( ll _x,ll _y )
        {
            x=_x,y=_y;
        }
        bool operator==( const point& rhs ) const {
            return x==rhs.x && y==rhs.y;
        }
        point operator -(const point &rhs ) const {
            return point(x-rhs.x,y-rhs.y);
        }
        point operator+( const point &rhs ) const {
            return point(x+rhs.x,y+rhs.y);
        }
        ll operator * ( const point &rhs ) const /// 叉积
            return 1ll*x*rhs.y-1ll*y*rhs.x;
        }
        ll dot( const point &rhs ) const /// 点积
            return 1ll*x+rhs.x+1ll*y*rhs.y;
        }
        void get() { x=read(),y=read(); }
    }O,p[maxn],w1[maxn],w2[maxn],A,B;
    int n,m1,m2;
     
    inline bool cmpA( point a,point b ) { return (a-A)*(b-A)>0; }
    inline bool cmpB( point a,point b ) { return (a-B)*(b-B)>0; }
     
    int c[maxn];
    ll ans=0;
    void add( int x ) { while( x<n ) c[x]++,x+=lowbit(x); }
    int query( int x ,int tt=0 ) { while( x ) tt+=c[x],x-=lowbit(x);return tt;}
     
    void solve( point *t,int m )
    {
        sort(t+1,t+1+m,cmpA);///以A点极角排序
        ans+=(1ll*m*(m-1))>>1;///先假设所有点对都能与线段相交
        forint i=1;i<=m;i++ ) t[i].tag=i;
        sort(t+1,t+m+1,cmpB);///以B点极角排序
        memset(c,0,sizeof(c));
        forint i=1;i<=m;i++ )///减去不能与线段相交的点对
        {
            ///这里假设线段点为P、Q  选出来的点对为 A、B  在画图过程中发现
            ///选出来的能交的点对        B点要以P排序在A前面而且以Q排序也要在A前面
            ///不是就减去   以树状数组解决这个区间问题
            ans-=query(t[i].tag);
            add(t[i].tag);
        }
    }
     
    int main()
    {
        n=read(),A.get(),B.get();
        forint i=1;i<=n;i++ ) p[i].get();
        forint i=1;i<=n;i++ )
        {
            if( (A-p[i])*(B-p[i])>0ll ) w1[++m1]=p[i];///利用叉积把点分为线段上下两部分
            else w2[++m2]=p[i];
        }
        solve(w1,m1);///第一种情况  两个点在同一侧
        solve(w2,m2);
     
        ans+=1ll*m1*m2;///第二种情况 两个点在不同侧  还是一样先假设所有点对都能与线段相交
     
        sort(w1+1,w1+m1+1,cmpA);///一样 以A点极角排序
        sort(w2+1,w2+m2+1,cmpA);
        forint i=1,bas=1;i<=m1;i++ )///减去不能与线段相交的点对
        {
            ///i 上侧   bas 下侧
            ///画图分析
            while( bas<=m2 && (w1[i]-A)*(w2[bas]-A)>0 ) ++bas;///叉积判断
            ans-=bas-1;
        }
     
        sort(w1+1,w1+m1+1,cmpB);///以B点极角排序
        sort(w2+1,w2+m2+1,cmpB);
        forint i=1,bas=1;i<=m2;i++ )
        {
            ///一样
            while( bas<=m1 && (w2[i]-B)*(w1[bas]-B)>0 ) ++bas;
            ans-=bas-1;
        }
        printf("%lld ",ans);
        return 0;
    }

    e题的题解可能在我大佬队友写完后贴出来(这个方向我是真不会).....
    看到最后的彩蛋 推荐纯音乐 Like Sunday,Like Rain ^-^

  • 相关阅读:
    村上春树的《海边的卡夫卡》与中日现实
    熊的甜蜜世界
    VS创建dll和调用dll
    DIRECTSHOW在VS2005中PVOID64问题和配置问题
    Vs 2008 解决方案的目录结构设置和管理
    SQL Server 2008中的代码安全(二):DDL触发器与登录触发器
    如何在自动SGA管理模式下调节参数设置
    将ORACLE数据库从归档改成非归档状态
    查看oracle数据库是否归档和修改归档模式(转)
    oracle TRANSLATE函数详解
  • 原文地址:https://www.cnblogs.com/yurenwuyu/p/12592602.html
Copyright © 2011-2022 走看看