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;
}