SCAU2020春季个人排位赛div2 #5

头文件见上一场的blog

A题:cf 632B

题意:详情见我上上篇文章(个人排位div2#3
题解:同上
代码:同上

B题:cf 627A

题意:给你s和x,可能存在正数a+b=s,且a xor b=x,问a,b可能的组合有多少种
题解:s=a+b,则s=a ^ b+2*(a&b),^是只表示两个数的相加,&是表示两个数的进位,某一位的xor如果是1,那么a和b在这一位必然一个是1一个是0,此时&必为0;如果某一位的xor是0,那么在这一位的a和b都是确定的要么都是1要么都是0,至于是哪个,这个由其他位决定,所以不用管它们
ac代码:

int main()
{
    #ifdef local
    freopen("in.txt", "r", stdin);
    #endif // local
    ll s,x,ans=1;
    scanf("%lld%lld",&s,&x);
    ll a=(s-x)/2;
    if(a<0||(a*2+x)!=s||(a&x)!=0)
    {
        printf("0");
    }
    else{//printf("okkk");
    ll t=0;
    while(x)
    {
        if(x%2==1)ans*=2;
        x>>=1;
    }
    if(a==0)ans=ans-2;
    printf("%lld",ans);
    }
    return 0;
}

C题:cf 623A

题意:有一个字符串,只包含a,b,c,每一个字符都可以和b相连,a,c只能和自己相连,给出所有的字符相互连接情况,复原该字符串(字符串可能不存在
题解:二分图染色——显然ac之间不能连接,其实作题目的补图,这个补图就是二分图了!标记所有连接情况,发现某个点和其他点都连接,填写b,然后往下填,优先填a,如果有连接的格子,也填a,不连接的话,填c。违规情况有两种:i和j连接,但是一个填了a一个填了c;i和j没有链接,但是他们填的是一样的字母
ac代码:

int n,m,flag=0;
int s[800][800];
char ans[600];
void dfs(int i)
{
    for(int j=0;j<n;j++)
    {
        if(i!=j&&s[i][j]==0&&ans[i]==ans[j])
        {
            flag=1;
        }
        if(i!=j&&s[i][j]==1&&((ans[i]=='a'&&ans[j]=='c')||(ans[i]=='c'&&ans[j]=='a')))
           {
               flag=1;
           }
        if(i!=j&&s[i][j]==0&&ans[j]==0)
            {
                if(ans[i]=='a')ans[j]='c';
                else if(ans[i]=='c')ans[j]='a';
                dfs(j);
            }
        if(i!=j&&s[i][j]==1&&ans[j]==0)
        {
            if(ans[i]=='a')ans[j]='a';
            else if(ans[i]=='c')ans[j]='c';
            dfs(j);
        }
    }
}
int main()
{
    #ifdef local
    freopen("in.txt", "r", stdin);
    #endif // local
    scanf("%d%d",&n,&m);
    while(m--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        s[a-1][b-1]=1;
        s[b-1][a-1]=1;
    }
    for(int i=0;i<n;i++)
    {
        int po=0;
        for(int j=0;j<n;j++)
        {
            if(i!=j&&s[i][j]==0)
                po=1;
        }
        if(po==0)
            ans[i]='b';
    }
    for(int i=0;i<n;i++)
    {
        if(ans[i]==0){
            ans[i]='a';
            dfs(i);
        }
    }
    if(flag==1)printf("No");
    else {
        printf("Yes\n");
        printf("%s",ans);
    }
    return 0;
}

D题:cf 604B

题意:n个铃铛,m个箱子,n<=2m,铃铛体积从第一个到最后一个递增,问要装下所有的铃铛,箱子体积统一,那么箱子最小要有多大
题解:由题意得,设有x个铃铛单独装箱,x=2
m-n,这x个肯定是取最大的那几个放,剩下的里面最大+最小为一箱,不断更新箱子体积就可以了
ac代码:

int a[150000];
int main()
{
    #ifdef local
    freopen("in.txt", "r", stdin);
    #endif // local
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)scanf("%d",&a[i]);
    if(m>=n)printf("%d",a[n-1]);
    else{
        int cnt,ans=a[n-1];
        cnt=2*m-n;
        cnt=n-cnt;
        for(int i=0;i<=cnt/2;i++)
            ans=max(ans,a[i]+a[cnt-i-1]);
        printf("%d",ans);

    }
    return 0;
}

E题:hdu 2098

题意:给你一个偶数,拆成两个素数的解,问有多少种拆法
题解:暴力求解就好啦(嚣张
ac代码:

bool prime(int n)
{
    if(n==2)return false;
    else if(n>2)
    {
        for(int i=2;i*i<=n;i++)
        {
            if(n%i==0)return false;
        }
        return true;
    }
}
int main()
{
    #ifdef local
    freopen("in.txt", "r", stdin);
    #endif // local
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)break;
        else
        {
            int ans=0;
            for(int i=2;i<n/2;i++)
            if(prime(i)&&prime(n-i))
                ans++;
                printf("%d\n",ans);
        }
    }
    return 0;
}

F题:poj 3259

题意:一个人从点1出发,走路经过若干条路去到某个点,再经由这个点走虫洞(可能不止一个)或者走路回到点1,且用时比去的时候少,问存在这种情况吗
题解:Bellman_Ford,负权有向图(是叫这个吗),就是维护每个点到源点的距离,如果这个点到源点的用时少于它的来点+走到它的用时,说明存在情况
ac代码:

int T,n,m,k;

struct NODE
{
    int from,to,dist;
};
vector<NODE>edge;
vector<int>g[1000];

void good(int n)
{
    for(int i=0;i<n;i++)g[i].clear();
    edge.clear();
}

void addnode(int from,int to,int dist)
{
    edge.push_back((NODE){from,to,dist});
    int k=edge.size();
    g[from].push_back(k-1);
}
bool BELLMAN_FORD(int s)
{
    int d[1000];
    for(int i=0;i<n;i++)d[i]=(i==s?0:inf);
    for(int i=1;i<n;i++)
    {
        for(int j=0;j<edge.size();j++)
        {
            NODE e=edge[j];
            if(d[e.from]<inf)
                d[e.to]=min(d[e.to],d[e.from]+e.dist);
        }
    }
    for(int i=0;i<edge.size();i++)
    {
        NODE e=edge[i];
        if(d[e.to]>d[e.from]+e.dist)return true;
    }
    return false;
}
int main()
{
    #ifdef local
    freopen("in.txt", "r", stdin);
    #endif // local
    scanf("%d",&T);
    while(T--)
    {
        good(n);
        scanf("%d%d%d",&n,&m,&k);
        while(m--)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            addnode(a-1,b-1,c);
            addnode(b-1,a-1,c);
        }
        while(k--)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            addnode(a-1,b-1,-c);
        }
        if(BELLMAN_FORD(0))printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

G题:cf 474D

题意:k的白花规模数,一把花有a~b朵花,一把花里的花可以是红花,或者红花+k*n朵白花(n>=0);且每一个k朵白花必须全部相连,比如说一把花有4朵,红花是R白花是W,这把花可以是RRWW,不可以是WRWR。给出a,b问有多少种花的组合方法
题解:DP,状态转移方程是:dp[i]=dp[i-1]+dp[i-k],dp[i-1]对应的是i位是红花的情况,dp[i-k]对应的是第i位是白花的情况,如果i是白花,那么i-k+1~i都是白花,dp[i]是对前面情况的继承
ac代码:

ll dp[101000],ans[101000];
int main()
{
    #ifdef local
    freopen("in.txt", "r", stdin);
    #endif // local
    int n,k,a,b;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        memset(dp,0,sizeof(dp));
        memset(ans,0,sizeof(ans));
        dp[0]=1;
        for(int i=1;i<=100005;i++)
        {
            if(i>=k)dp[i]=(dp[i-1]+dp[i-k])%mod;
            else dp[i]=dp[i-1];
        }
        for(int i=1;i<=100005;i++)
        {
            ans[i]=(ans[i-1]+dp[i])%mod;
        }
        //for(int i=1;i<=5;i++)printf("**%lld  %lld",dp[i],dp[])
        while(n--)
        {
            scanf("%d%d",&a,&b);
            ll sum=0;
            sum=(ans[b]-ans[a-1]+mod)%mod;
            printf("%lld\n",sum);
        }
    }
    return 0;
}

H题:hdu 1166

题意:有n个营地,每个营地有若干个士兵,可以对这些营地进行加兵,减兵,数兵的操作,数兵会给出范围a~b,数兵的时候输出总数
题解:线段树维护局部和,板子题
我学习的线段树模板来自:点进去就好啦
ac代码:

const int maxn=500010*4;
using namespace std;
int a[maxn];

struct TREE
{
    int l,r,sum;
}node[maxn];


void pushup(int i)
{
    node[i].sum=node[i<<1].sum+node[(i<<1)|1].sum;
}

void build(int i,int l,int r)
{
    node[i].l=l;node[i].r=r;
    if(l==r)
       {
           node[i].sum=a[l];return;
       }
    int mid=(l+r)/2;
    build(i<<1,l,mid);
    build((i<<1)|1,mid+1,r);
    pushup(i);
}
int getsum(int i,int l,int r)
{
    if(node[i].l==l&&node[i].r==r)return node[i].sum;
    int mid=(node[i].l+node[i].r)/2;
    if(r<=mid)return getsum(i<<1,l,r);
    else if(l>mid)return getsum((i<<1)|1,l,r);
    else return (getsum(i<<1,l,mid)+getsum((i<<1)|1,mid+1,r));
}

void add(int i,int k,int v)
{
    if(node[i].l==k&&k==node[i].r){node[i].sum+=v;return;}
    int mid=(node[i].l+node[i].r)/2;
    if(k<=mid)  add(i<<1,k,v);
    else  add((i<<1)|1,k,v);
    pushup(i);
}

int main()
{
    #ifdef local
    freopen("in.txt", "r", stdin);
    #endif // local
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        memset(a,0,sizeof(a));
        int n;
        scanf("%d",&n);getchar();
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        build(1,1,n);
        int k,v;
        char s[10];
        printf("Case %d:\n",cas++);
        while(scanf("%s",s)!=EOF)
        {
            if(s[0]=='E')break;
            scanf("%d%d",&k,&v);
            if(s[0]=='A')add(1,k,v);
            if(s[0]=='S')add(1,k,-v);
            if(s[0]=='Q')printf("%d\n",getsum(1,k,v));
            getchar();
        }

    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值