寒假训练2021-1-26

组队训练
基本上队友都是各打各的,而且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);
}

猜你喜欢

转载自blog.csdn.net/weixin_45948940/article/details/113198902