组队训练
基本上队友都是各打各的,而且VJ很卡 ,就提前下班了
ACEJ都是大水题,正常人都可以秒
B题 由于太卡了,一直没等到评测结果,赛后过了。
题意简化: 两个篮子分别有M,N个饼干,现在M篮子最多减少X个饼干,N篮子最多减少Y个饼干,现在有两个人,分小明先手,小绿后手拿饼干,每次可以拿K个饼干(k>0) 而且M-K 是M的正因数,当一个人操作的时候现场两个篮子都是1个饼干,那么他就输了。现在求有多少个二元组(M-x,N-y)使得先手必胜。
分析: emmm 这显然是个博弈 因为拿走了K个饼干,而剩下的M-K 必须是M的因数 (M指没拿的时候的饼干数量) 那么K*(M-K)一定可以写成M的唯一分解形式,换言之相当于一场这样的博弈
两堆石头 分别有num1个石头 和 num2 个石头
每次可以拿走<=当前石头个数的任意值 谁不能操作 谁就输
(等价于原题意中的两堆饼干数量为1) 因为你相当于是每次拿质因子,质因子一旦拿完 就只剩下1了 。那么不难看出,(M-x,N-y)质因子总数不同时,先手必胜 。 跑一遍欧拉筛+枚举分解质因子 +算贡献就OK 我的代码跑了1.3s
ll prime[1000700],minprime[1000700];
ll c=0;
void euler(int n) //欧拉筛
{
int i,j;
for(i=2; i<=n; i++)
{
if(!minprime[i])
prime[++c]=i,minprime[i]=i;
for(j=1; j<=c&&i*prime[j]<=n; j++)
{
minprime[i*prime[j]]=prime[j];
if(i%prime[j]==0)
break;
}
}
}
ll num[5000555];
void check(ll x){
//质因子分解
ll op=x;
for(int j=1;j<=c;j++){
if(prime[j]*prime[j]>x) break;
ll xx=0;
if(x%prime[j]==0){
while(x%prime[j]==0) x/=prime[j],xx++;
num[op]+=xx;
}
}
if(x>1)
{
num[op]++;
}
}
map<ll,ll>s1;
signed main(){
ll n,m,x,y;
read(n);
read(m);
read(x);
read(y);
ll rnmg=1e6+7;
euler(rnmg);
for(int i=min(n-x,m-y);i<=max(n,m);i++){
check(i);
}
for(int i=m;i>=m-y;i--){
s1[num[i]]++;
}
long long int ans=0;
long long int rnm=1ll*(x+1)*(y+1);
for(int i=n;i>=n-x;i--){
ans+=s1[num[i]];
}
printf("%lld",rnm-ans);
}
F其实是个傻逼题
大概意思是 n 个怪物排排站,要消灭它就要损耗玩家Di的hp,同时会掉落一个血包,提高人物的最大生命值(意思就是能够直接在hp的基础上+Ri,而不是到了初始血量就不增加了,这里很坑,要看样例3才明白) 问我们如果能通关,要用最少的血包数,如果不能通关,问我们能最多打到第几关。
直接模拟,用优先队列每次如果hp<Di 就取队首来填充
struct pe
{
ll D,R;
} boss[222222];
priority_queue<ll>q;
signed main()
{
ll s,n;
read(n);
read(s);
ll ma=s;
for(int i=1; i<=n; i++)
{
read(boss[i].D);
}
for(int i=1; i<=n; i++)
{
read(boss[i].R);
}
ll f=0;
ll cnt=0;
for(int i=1; i<=n; i++)
{
if(s>=boss[i].D)
{
s-=boss[i].D;
q.push(boss[i].R);
continue;
}
while(s<boss[i].D&&q.size())
{
ll ok=q.top();
q.pop();
s=s+ok;
cnt++;
}
if(s<boss[i].D)
{
f=i-1;
break;
}
else
{
s=s-boss[i].D;
q.push(boss[i].R);
}
}
if(f)
{
printf("LOSE\n%lld",f);
}
else
{
printf("WIN\n%lld",cnt);
}
}
heavy sort G题
大概意思是一堆物品,有高度hi,重量wi ,现在你可以交换相邻两个数的位置花费他们重量的乘积,现在要求 使得整个物品排列的高度从低到高的最小花费。
分析: 思考了一下
如果说从1到pos 已经是升序了(第1小,第2小,这样), 那么后面的物品移动前面有序的物品是不会产生贡献的。那么 如图
假设,对高度排序以后,我们枚举第i 小的数,假设它的原始位置处于cnt,那么把它移动到最前面要花费的是前面的Σwi 那么cnt这个位置的值应该被删掉,并且重新维护前缀和。想到这里就很简单了,直接结构体+线段树区间求和+单休就OK
#include<bits/stdc++.h>
#include<stdlib.h>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<time.h>
#include <cstdio>
#include <iostream>
#include <vector>
#define ll long long
#define int long long
#define inf 0x3f3f3f3f
#define mods 1000000007
#define modd 998244353
#define PI acos(-1)
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
#define si size()
#define E exp(1.0)
#define fixed cout.setf(ios::fixed)
#define fixeds(x) setprecision(x)
#define IOS ios::sync_with_stdio(false);cin.tie(0)
using namespace std;
ll gcd(ll a,ll b){
if(a<0)a=-a;if(b<0)b=-b;return b==0?a:gcd(b,a%b);}
template<typename T>void read(T &res){
bool flag=false;char ch;while(!isdigit(ch=getchar()))(ch=='-')&&(flag=true);
for(res=ch-48;isdigit(ch=getchar());res=(res<<1)+(res<<3)+ch - 48);flag&&(res=-res);}
ll lcm(ll a,ll b){
return a*b/gcd(a,b);}
ll qp(ll a,ll b,ll mod){
ll ans=1;if(b==0){
return ans%mod;}while(b){
if(b%2==1){
b--;ans=ans*a%mod;}a=a*a%mod;b=b/2;}return ans%mod;}//快速幂%
ll qpn(ll a,ll b, ll p){
ll ans = 1;a%=p;while(b){
if(b&1){
ans = (ans*a)%p;--b;}a =(a*a)%p;b >>= 1;}return ans%p;}//逆元 (分子*qp(分母,mod-2,mod))%mod;
ll a[222222];
struct pe{
ll vel;
ll pos;
ll w;
}sb[222222];
bool cmp(pe x,pe y){
return x.vel<y.vel;
}
#define il inline
struct Tree
{
ll l,r,sum,lazy,maxn,minn;
} tree[880000];
il void push_up(ll rt)
{
tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum;
tree[rt].maxn=max(tree[rt<<1].maxn,tree[rt<<1|1].maxn);
tree[rt].minn=min(tree[rt<<1].minn,tree[rt<<1|1].minn);
}
il void push_down(ll rt, ll length)
{
if(tree[rt].lazy)
{
tree[rt<<1].lazy+=tree[rt].lazy;
tree[rt<<1|1].lazy+=tree[rt].lazy;
tree[rt<<1].sum+=(length-(length>>1))*tree[rt].lazy;
tree[rt<<1|1].sum+=(length>>1)*tree[rt].lazy;
tree[rt<<1].minn+=tree[rt].lazy;
tree[rt<<1|1].minn+=tree[rt].lazy;
tree[rt<<1].maxn+=tree[rt].lazy;
tree[rt<<1|1].maxn+=tree[rt].lazy;
tree[rt].lazy=0;
}
}
il void build(ll l, ll r, ll rt, ll *aa)
{
tree[rt].lazy=0;
tree[rt].l=l;
tree[rt].r=r;
if(l==r)
{
tree[rt].sum=aa[l];
tree[rt].minn=tree[rt].sum;
tree[rt].maxn=tree[rt].sum;
return;
}
ll mid=(l+r)>>1;
build(l,mid,rt<<1,aa);
build(mid+1,r,rt<<1|1,aa);
push_up(rt);
}
il void update_range(ll L, ll R, ll key, ll rt)
{
if(tree[rt].r<L||tree[rt].l>R)
return;
if(L<=tree[rt].l&&R>=tree[rt].r)
{
tree[rt].sum+=(tree[rt].r-tree[rt].l+1)*key;
tree[rt].minn+=key;
tree[rt].maxn+=key;
tree[rt].lazy+=key;
return;
}
push_down(rt,tree[rt].r-tree[rt].l+1);
ll mid=(tree[rt].r+tree[rt].l)>>1;
if(L<=mid)
update_range(L,R,key,rt << 1);
if(R>mid)
update_range(L,R,key,rt << 1 | 1);
push_up(rt);
}
il ll query_range(ll L, ll R, ll rt)
{
if(L<=tree[rt].l&&R>=tree[rt].r)
{
return tree[rt].sum;
}
push_down(rt,tree[rt].r-tree[rt].l+1);
ll mid=(tree[rt].r+tree[rt].l)>>1;
ll ans=0;
if(L<=mid)
ans+=query_range(L,R,rt << 1);
if(R>mid)
ans+=query_range(L,R,rt << 1 | 1);
return ans;
}
il ll query_min(ll L,ll R,ll rt)
{
if(L<=tree[rt].l&&R>=tree[rt].r)
{
return tree[rt].minn;
}
push_down(rt,tree[rt].r-tree[rt].l+1);
ll mid=(tree[rt].r+tree[rt].l)>>1;
ll ans=(0x3f3f3f3f3f3f3f3fll);
if(L<=mid)
ans=min(ans,query_min(L,R,rt << 1));
if(R>mid)
ans=min(ans,query_min(L,R,rt << 1 | 1));
return ans;
}
il ll query_max(ll L, ll R, ll rt)
{
if(L<=tree[rt].l&&R>=tree[rt].r)
{
return tree[rt].maxn;
}
push_down(rt,tree[rt].r-tree[rt].l+1);
ll mid=(tree[rt].r+tree[rt].l)>>1;
ll ans=-(0x3f3f3f3f3f3f3f3fll);
if(L<=mid)
ans=max(ans,query_max(L,R,rt << 1));
if(R>mid)
ans=max(ans,query_max(L,R,rt << 1 | 1));
return ans;
}
signed main()
{
ll n;
read(n);
for(int i=1; i<=n; i++)
{
read(sb[i].vel);
sb[i].pos=i;
}
for(int i=1; i<=n; i++)
{
read(a[i]);
sb[i].w=a[i];
}
sort(sb+1,sb+1+n,cmp);
build(1,n,1,a);
ll ans=0;
for(int i=1; i<=n; i++)
{
ans=ans+(sb[i].w)*query_range(1,sb[i].pos-1,1);
update_range(sb[i].pos,sb[i].pos,-sb[i].w,1);
}
printf("%lld",ans);
}