首页 > 其他 > 详细

AtCoder-abc147 (题解)

时间:2019-12-12 09:58:34      阅读:162      评论:0      收藏:0      [点我收藏+]

A - Blackjack (水题)

题目链接

大致思路:

水题


B - Palindrome-philia (水题)

题目链接

大致思路:

由于整个串是回文串,只要判断前一半和后一半有多少个不同即可


C - HonestOrUnkind2 (暴力)

题目链接

大致思路:

\(N\) 只有15,直接枚举出所有的情况 \(2^N\) 种,对每一种方案判断合法性即可,只要找诚实的人来判断。


点击展开代码

#include<bits/stdc++.h>
using namespace std;
vector<int>x[20],y[20];
int n;
int js(int x){
    int ans=0;
    while(x){
        ans+=(x&1);
        x>>=1;
    }
    return ans;
}
bool check(int X){
    int temp[20]={0};
    for(int i=1;i<=n;i++){
        if((X>>(i-1))&1)temp[i]=1;
        else temp[i]=0;
    }
    for(int i=1;i<=n;i++){
        if(temp[i]){
            int siz=x[i].size();
            for(int j=0;j<siz;j++){
                int id=x[i][j];
                if((temp[id]^y[i][j])==1)return 0;
            }
        }
    }
    return 1;
}
int main()
{
    //freopen("H:\\c++1\\in.txt","r",stdin);
    //freopen("H:\\c++1\\out.txt","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int m;
        scanf("%d",&m);
        while(m--){
            int a,b;
            scanf("%d%d",&a,&b);
            x[i].push_back(a);y[i].push_back(b);
        }
    }
    int mx=(1<<n);
    int ans=0;
    for(int i=0;i<mx;i++){
        if(check(i)){
            ans=max(ans,js(i));
        }
    }
    printf("%d\n",ans);
    return 0;
}

D - Xor Sum 4 (按位计算)

题目链接

题目大意:

给定 \(n\) 个数字,要求求出 \(\sum^{n-1}_{i=1}\sum^{n}_{j=i+1}a_i\ xor\ a_j\)

大致思路:

我们将每一位单独计算贡献,比如讨论第 \(i\) 位,那么把 \(n\)个数字的第 \(i\) 位取出来,\(b_1,b_2,...,b_n\) 那么对于\(b_j\) 如果是 \(0\) ,那么能 \(xor\)\(1\) 的个数为 \([j+1,n]\)\(1\) 的个数。最后把所有计算 \(1\) 的个数相加\(*2^i\) ,那么这就是该位对答案的贡献了。复杂度为 \(O(n*60)\)


点击展开代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=3e5+10;
const int mod=1e9+7;
ll a[N],p[N];
ll sum[N];
int n;
int main()
{
    //freopen("H:\\c++1\\in.txt","r",stdin);
    //freopen("H:\\c++1\\out.txt","w",stdout);
    p[0]=1;
    for(int i=1;i<=100;i++)p[i]=(p[i-1]*2)%mod;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    ll ans=0;
    for(ll i=0;i<=60;i++){
        for(int j=1;j<=n;j++){
            if((a[j]>>i)&1)sum[j]=sum[j-1]+1;
            else sum[j]=sum[j-1];
        }
        ll cnt=0;
        for(int j=1;j<n;j++){
            if((a[j]>>i)&1){
                cnt+=(n-j-(sum[n]-sum[j]));
            }else{
                cnt+=(sum[n]-sum[j]);
            }
        }
        cnt%=mod;
        ans=(ans+(1ll*cnt*p[i]%mod))%mod;
    }
    printf("%lld\n",ans);
    return 0;
}

E - Balanced Path (DP)

题目链接

题目大意:

给一个矩阵,每一个位置有两个数字,现在从左上走到右下,每次将位置的两个数字一个标记红色,一个标记蓝色,问 \(红色数字蓝色数字|\sum{红色数字}-\sum{蓝色数字}|\) 最小是多少

大致思路:

感觉就很像 \(dp\) ,用 \(dp[i][j][k]\) 表示走到 \((i,j)\) ,对于差值为 \(k\) 能否得到,假设当前走到 \((i,j)\) ,两个数字的差值为 \(cha=|a_{ij}-b_{ij}|\) 那么状态转移就是

\(dp[i][j][k\pm cha]=dp[i-1][j][k]\ if(dp[i-1][j][k]=True)\)

\(dp[i][j][k\pm cha]=dp[i][j-1][k]\ if(dp[i][j-1][k]=True)\)

可以用bitset来优化

代码:


点击展开代码

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int N=100;
const int M=6401;
const int Y=6400;
bitset<M*2> dp[N][N];
int n,m;
int a[N][N],b[N][N];
int main()
{
    //freopen("H:\\c++1\\in.txt","r",stdin);
    //freopen("H:\\c++1\\out.txt","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)scanf("%d",&a[i][j]);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)scanf("%d",&b[i][j]);
    dp[1][0][Y]=1;dp[0][1][Y]=1;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++){
        int cha=abs(a[i][j]-b[i][j]);
        dp[i][j]|=((dp[i-1][j]<<cha)|(dp[i-1][j]>>cha));
        dp[i][j]|=((dp[i][j-1]<<cha)|(dp[i][j-1]>>cha));
    }
    int ans=inf;
    for(int i=0;i<M*2;i++){
        if(dp[n][m][i])ans=min(ans,abs(i-Y));
    }
    printf("%d\n",ans);
    return 0;
}     

F - Sum Difference (数学)

题目链接

题目大意:

给一个 \(n\) 个数的等差数列,首项为 \(x\) ,公差为 \(d\) ,现在在数列中选择 \(k\) 个数,设计 \(S\)\(k\) 个数的和, \(T\) 为剩下 \(n-k\) 的数的和。为共有多少个 \(S-T\) 的值。

大致思路:

假设所有数字之和为 \(sum\) ,那么 \(S-T=S-(sum-S)=2*S-sum\) ,那么其实就是求 \(S\) 的不同值的个数。假设 \(S=k*x+m*d\) ,其中 \(k\) 就是选择的数的个数, \(m\) 是一个值, \(m\) 应该在 \([0+1+...+k-1,n-k+n-(k+1)+...+n-1]\) 的范围之内。那么对于一个 \(k\) 值, \(S\) 的值就是在一个 \([L,R]\) 中,然后每一个数字间隔 \(d\) ,而且这些值 \(S\%d\) 都是相等的。那么我们就对所有的 \(S\)\(d\) 将它们分成一个剩余系,不同剩余类中的元素是不会相等的,决定其位于哪个剩余类是 \(k*x\%d\) 的值。为了得到每一个剩余类的元素个数,我们将S/d,那么就会得到许多的区间,按照k*x%d分类,对于每一个类将区间排序,合并,计算即可。

感觉比较抽象,具体来说就是,一个模d余0剩余类中的数字为 \(,,,,x,x+d,x+2*d,x+3*d,...\) ,那么一个模d余1剩余类的数字为 \(,,,x+1,x+1+d,x+1+2*d,....\) ,那么我们就对每一个剩余类来求解。

代码:


点击展开代码

#include<bits/stdc++.h>
#define fi first
#define se second
#define ll long long
using namespace std;
const int N=2e5+10;
struct node{
    ll l,r;
    bool operator < (const node &x)const{
        if(l!=x.l)return l<x.l;
        return r<x.r;
    }
    node(ll a=0,ll b=0){l=a,r=b;}
};
map<ll,vector<node> >s;
ll n,x,d;
ll sum[N];
int main()
{
    //freopen("H:\\c++1\\in.txt","r",stdin);
    //freopen("H:\\c++1\\out.txt","w",stdout);
    for(int i=1;i<N;i++)sum[i]=sum[i-1]+i;
    scanf("%lld%lld%lld",&n,&x,&d);
    if(x==0&&d==0){
        puts("1");return 0;
    }
    if(x!=0&&d==0){
        printf("%lld\n",n+1);return 0;
    }
    if(d<0)d*=-1,x*=-1;
    ll L=0,R=0;
    for(ll i=0;i<=n;i++){
        ll t=i*x;
        L=sum[i-1];
        R=sum[n-1]-sum[max(0ll,n-i-1)];
        L+=t/d,R+=t/d;
        t%=d;
        if(t<0)t+=d,L--,R--;
        s[t].push_back(node(L,R));
    }
    ll ans=0;
    for(auto it:s){
        sort(it.se.begin(),it.se.end());
        L=it.se[0].l,R=it.se[0].r;
        for(node v:it.se){
            if(v.l>R){
                ans+=R-L+1;
                L=v.l,R=v.r;
            }
            else{
                R=max(v.r,R);
            }   
        }
        ans+=R-L+1;
    }
    printf("%lld\n",ans);
    return 0;
}

<\details>

AtCoder-abc147 (题解)

原文:https://www.cnblogs.com/C-W-K/p/12013626.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!