2019 Multi-University Training Contest 6

Stay Real

题意:给你一个树,每个点有点权,并且编号为 i 的点的父亲节点是 i/2,1为根节点,根节点没有父亲节点。A和B两个人轮流取点,只能选叶子节点,选完之后这个点从从树上删除,并且这个人叶子节点的点权加到这个人的得分上。并且题目保证,父亲节点的点权一定大于子节点的点权。A和B两个人都想让自己的得分最高,A先手,输出A和B的最终得分。

用优先队列贪心即可,每次贪心选择点权最大的叶子节点,然后判断他的父亲节点是不是变成了叶子,如果变成了叶子的话,就把他加到优先队列里,知道队列为空,或者说直到选到1节点,因为1节点肯定是最后一次选到的节点。

#include<bits/stdc++.h>
#define mem(a,b) memset((a),b,sizeof(a))
#define de cout<<endl<<endl<<endl
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=100010;
using namespace std;
struct node{
    int id;
    ll num;
    friend bool operator <(const node a,node b)
    {
        return a.num<b.num;
    }
}a[100010];
int son[100010],n;
priority_queue<node> q;
void init()
{
    for(int i=0;i<=n;i++)
        son[i]=0;
}
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i].num);
            a[i].id=i;
            if(i*2<=n)
                son[i]++;
            if(i*2+1<=n)
                son[i]++;
        }
        for(int i=1;i<=n;i++)
            if(son[i]==0)
                q.push(a[i]);
        int cnt=0;
        ll ans1=0,ans2=0;
        while(1)
        {
            cnt++;
            node p=q.top();
            q.pop();
            if(cnt&1)
                ans1+=p.num;
            else
                ans2+=p.num;
            if(p.id==1)
                break;
            son[p.id/2]--;
            if(son[p.id/2]==0)
                q.push(a[p.id/2]);
        }
        printf("%lld %lld\n",ans1,ans2);
    }
    return 0;
}

TDL

题意:定义函数 f (n,m):表示大于n且与n互质的第m小的数。输入k和m,求满足(f(n,m)-n)^n=k的解的n的个数。(^表示亦或)

直接枚举k-1000到k+1000,如果满足题意,ans++,最后输出ans即可。注意:0 和任何数都不互质,因为 0 和任何数的gcd都等那个数本身。

#include<bits/stdc++.h>
#define mem(a,b) memset((a),b,sizeof(a))
#define de cout<<endl<<endl<<endl
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=100010;
using namespace std;
ll getf(ll n,ll m)
{
    ll ret=0;
    for(ll i=n+1;i;i++)
    {
        if(gcd(i,n)==1)
            m--;
        if(m==0)
            {ret=i;break;}
    }
    return ret;
}
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        ll k,m;
        scanf("%lld%lld",&k,&m);
        int f=0;
        ll ans;
        for(ll i=k-1010;i<=k+1010;i++)
        {
            if(i==0)
                continue;
            ll n=i;
            if(((getf(n,m)-n)^n)==k)
                {ans=n;f++;break;}
        }
        if(f)
            printf("%lld\n",ans);
        else
            printf("-1\n");
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值