“蔚来杯“2022牛客暑期多校训练营4

D-Jobs (Easy Version)

题意:

给你n个公司的求职岗位,每个岗位有三个要求:EQ、IQ、AQ,当你的这三项数值都大于等于其中任意一个职位的标准时,这个公司就会邀请你入职。现在你有q个朋友,你要算出他们分别会被多少个公司邀请,再根据公司的数量算出: 其中ans是第i个朋友收到公司邀请的数目,seed是题目给我们的随机数种子。

题解:

显然我们只需知道第i个朋友收到公司邀请的数目,再按照公式求值即可。首先想到一个个试探,但是此时时间复杂度为q*n*m显然超时,故要优化查询。

(1)可以想到我们只需判断每个朋友的三商是否满足每个公司最容易入职的岗位的要求就行了。

(2)我们可以采用类似二维前缀和的方式,我们准备一个二维数组,把IQ看成i,EQ看成j,AQ为v[i][j],那么对于朋友的三商abc来说,只要v[a][b]小于等于c,那么这个公司就是能够邀请我们的。

(3)然而我们还需要一维作为第i个公司,故最后定义一个三维数组,v[i][j][k]表示在第i个公司中第当职员IQ为j,EQ为k最少需要v[i][j][k]的AQ。

#include <bits/stdc++.h>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
#define endl '\n'
#define N  100005
#define fi first
#define se second
#define pb push_back
using namespace std;
const int inf=0x3f3f3f3f;
const double ex=acos(-1);
const int mod=998244353;
int gcd(int a,int b){return b? gcd(b,a%b) : a ;}
typedef pair<int,int>PII;
priority_queue<int,vector<int>,greater<int> > p;//小根堆
int  v[20][405][405];
int  n,ans,seed,q;
int qsm(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1) res=res*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return res;
}
int solve(int IQ,int EQ,int AQ,int i)
{
    int res=0;
    for(int i=1;i<=n;i++)
    {
        if(v[i][IQ][EQ]<=AQ) res++;
    }
    ans=(ans+res%mod*qsm(seed,q-i)%mod)%mod;
    return res;
}
signed main()
{ios
    int m,a,b,c;
    cin >>n>>q;
    for(int i=1;i<=n;i++)
    {
        cin >>m;
        memset(v[i],inf,sizeof(v[i]));
        for(int j=1;j<=m;j++)
        {
            cin >>a>>b>>c;
            v[i][a][b]=min(v[i][a][b],c);
        }
        for(int j=1;j<=400;j++)
        {
            for(int k=1;k<=400;k++)
            {
                v[i][j][k]=min(v[i][j][k],v[i][j-1][k]);
                v[i][j][k]=min(v[i][j][k],v[i][j][k-1]);
            }
        }
    }
    cin >>seed;
    std::mt19937 rng(seed);
    std::uniform_int_distribution<> u(1,400);
    int lastans=0;
    for (int i=1; i<=q; i++)
    {
        int IQ=(u(rng)^lastans)%400+1;  // The IQ of the i-th friend
        int EQ=(u(rng)^lastans)%400+1;  // The EQ of the i-th friend
        int AQ=(u(rng)^lastans)%400+1;  // The AQ of the i-th friend
        lastans=solve(IQ,EQ,AQ,i);  // The answer to the i-th friend
    }
    cout <<ans;
    return 0;
}

H-Wall Builder II

题意:

题解:

K-NIO's Sword

题意:

NOI有一把初始能量为A=0的剑,前方有n个敌人,可以在某一时刻将宝剑的能量升级:如果原来能量为 ,升级之后能量变为 A ∗ 10 + x ,x 为 0 − 9中任选的一个数。
如果想要击败第 i   (2≤i≤n) 只怪兽,需要保证第 i − 1只怪兽已经被击败。
在击败第 i 只怪兽时,宝剑的能量 a 需满足 A ≡ i ( mod  n) . 问,击败所有怪兽最少需要升级多少次?

题解: 

当我们正在消灭第i个敌人时,对于i-1有A%n==(i-1)%n,故A==n*k+i-1;设需要k次可使得A%n==i%n;则k次后能量变为A*10^k+x(0<x<10^k),因为(A*10^k+x)%n==i%n,又A==n*k+i-1,故A的大小对于消灭第i个敌人没有关系,则取A==i-1。通过枚举k的次数来求得x是否合法。将公式((i-1)*10^k+x)%n==i%n变形得x==(i-(i-1)*10^k)%n,但是考虑到该式x可能为负数,故x==((i-(i-1)*10^k)%n+n)%n,求得x<10^k则可以满足,否则继续枚举。由题可知n的范围为10^6,故最多6次内可找到合题意的解。

#include <bits/stdc++.h>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
#define endl '\n'
#define N  2000005
#define fi first
#define se second
#define pb push_back
using namespace std;
const int inf=0x3f3f3f3f;
const double ex=1e-7;
const int mod=1e9+7;
int gcd(int a ,int b){ return b ? gcd(b,a%b) : a ;}
typedef pair<int,int>PII;
priority_queue<int,vector<int>,greater<int> > q;
int v[7]={1,10,100,1000,10000,100000,1000000};
void solve()
{
    int n,ans=0;
    cin >>n;
    if(n==1) cout <<0<<endl;
    else
    {
        for(int i=1;i<=n;i++)
        {
            int k;
            for(k=1;k<=6;k++)
            {
                int x=((i-v[k]*(i-1))%n+n)%n;
                if(x<v[k]) break;
            }
            ans+=k;
        }
        cout <<ans<<endl;
    }
}
signed main()
{ios
     int t = 1;
    //cin >>t;
    while(t--)
    {
        solve();
    }
    return 0;
}

N-Particle Arts

题意:

给一组粒子能量,求该粒子能量的方差。

题解:

由题可知两粒子可发生碰撞,设一粒子能量为a,另外一粒子能量为b,碰撞后产生能量为a&b和a|b两粒子,最终该组粒子的方差总是不变的。可得:

(1)a+b=a&b+a|b;

(2)经观察发现a和b对应的二进制数的位置可移动,若a为01001,b为11100,则碰撞后有:01000,11101,即同一位时,1可与0交换,故可得将所有1全补给0的位置,这样可以减少很多大数据计算。

(3)值得注意的是方差的计算,需要输出分子和分母的最简式,故需要将方差公式化一下,本人第一次提交未通过,后来发现是数据范围太小了,需要开__int128才行,但是cin,cout不支持输出__int128类型的,故最后输出时强制转化一下

#include <bits/stdc++.h>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
#define endl '\n'
#define N  100005
#define fi first
#define se second
#define pb push_back
using namespace std;
const int inf=0x3f3f3f3f;
const double ex=acos(-1);
const int mod=998244353;
__int128 gcd(__int128 a,__int128 b){return b? gcd(b,a%b) : a ;}
typedef pair<int,int>PII;
priority_queue<int,vector<int>,greater<int> > p;//小根堆
void solve()
{
    int n,x,sum=0,v[20]={0};
    __int128 fz=0,fm=0;
    cin >>n;
    for(int i=1;i<=n;i++)
    {
        cin >>x;
        sum+=x;
        for(int i=0;x!=0;i++)
        {
            v[i]+=x&1;
            x>>=1;
            //cout <<v[i]<<" ";
        }
        //cout <<endl;
    }
    for(int i=1;i<=n;i++)
    {
        x=0;
        for(int j=0;j<=15;j++)
        {
            if(v[j])
            {
                x+=(1<<j);
                v[j]--;
            }
        }
        fz+=(n*x-sum)*(n*x-sum);
    }
    fm=n*n*n;int k=gcd(fz,fm);
    fz=fz/k;
    fm=fm/k;
    cout <<(int)fz<<"/"<<(int)fm;
}
signed main()
{ios
    int t = 1;
    //cin >> t;
    while(t--)
    {
        solve();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值