“蔚来杯“2022牛客暑期多校训练营4
觉得有帮助的点个赞!
比赛地址
参考的大佬题解
怒写一夜题解,第一次一天补一场,继续加油!
A Task Computing
#include<bits/stdc++.h>
using namespace std;
#define db double
const int N = 1e5 + 10;
struct Node{
db w;
db p;
bool operator < (const Node &t) const {
return w + p * t.w < t.w + t.p * w;
}
}a[N];
db f[N][30]; //f[i][j]表示前i件物品中拿j件的最大价值
int n, m;
int main()
{
cin>>n>>m;
for(int i = 1; i <= n; i ++ ){
cin>>a[i].w;
}
for(int i = 1; i <= n; i ++ ){
cin>>a[i].p;
a[i].p /= 10000;
}
sort(a + 1, a + n + 1);
for(int i = 1; i <= n; i ++ ){
for(int j = 1; j <= min(i, m); j ++ ){
f[i][j] = max(f[i - 1][j], a[i].w + a[i].p * f[i - 1][j - 1]);
}
}
printf("%.12f", f[n][m]);
return 0;
}
D Jobs (Easy Version)
#include<bits/stdc++.h>
#include <random>
using namespace std;
const int N = 410, M = 2e6 + 10, mod = 998244353;
int dp[12][N][N]; //dp[i][j][k]记录第i个公司要求 IQ <= i, EQ <= j,的职位的最低AQ要求
int n, m;
long long qq[M];
long long ans;
int solve(int IQ, int EQ, int AQ){
int res = 0;
for(int i = 1; i <= n; i ++ ){
if(dp[i][IQ][EQ] <= AQ) res ++ ;
}
return res;
}
signed main()
{
cin>>n>>m;
memset(dp, 0x3f3f3f3f, sizeof dp);
for(int i = 1; i <= n; i ++ ){
int cnt;
cin>>cnt;
while(cnt -- ){
int a, b, c;
cin>>a>>b>>c;
dp[i][a][b] = min(dp[i][a][b], c);
}
//二维偏序操作
//原本dp[i][k][d]记录的是第i个公司IQ=k,EQ=d的职位的最低阿Q值
//经过二维偏序dp[i][k][d]就变成记录i个公司IQ <= k,EQ <= d的职位的最低阿Q值
//我在这卡了半天思维,不懂得话可以带几组数据或者去B站听emo的面向新手讲题
for(int k = 1; k <= 400; k ++ ){
for(int d = 1; d <= 400; d ++ ){
dp[i][k][d] = min(dp[i][k][d], dp[i][k - 1][d]);
dp[i][k][d] = min(dp[i][k][d], dp[i][k][d - 1]);
}
}
}
int seed;
cin>>seed;
std::mt19937 rng(seed);
std::uniform_int_distribution<> u(1,400);
qq[0] = 1;
for(int i = 1; i <= m; i ++ ){
qq[i] = (qq[i - 1] * seed) % mod;
}
int lastans=0;
for (int i=1;i<=m;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); // The answer to the i-th friend
ans = (ans + lastans * qq[m - i]) % mod;
}
cout<<ans<<endl;
return 0;
}
H Wall Builder II
这一题的铺砖的思路可以好好学学,还有长宽越接近,面积一定的矩形边长最短这个结论
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int T;
int n;
int s, y, x;
int a[N];
int main()
{
cin>>T;
while(T -- ){
cin>>n;
memset(a, 0, sizeof a);
s = 0, x = 0, y = 0; //初始化大矩形的长宽
for(int i = 1; i <= n; i ++ ){
s += i * (n - i + 1); //记录面积,宽度为1,长度*数量
a[i] = n - i + 1; //长度为i的木板有(n - i + 1)块
}
for(int t = 1; t * t <= s; t ++ ){
if(s % t == 0) y = t; //y记录最多铺几层
}
x = s / y; //每一层最多铺多长
int sl = 2 * x + 2 * y; //周长
cout<<sl<<endl;
for(int i = 1; i <= y; i ++ ){ //一层一层铺
int cur = 0; //每一层的起点从最左端开始,记录铺的砖块的左端
for(int k = n; k >= 1; k -- ){ //枚举这一块砖的宽度,从大往小铺
while(a[k] && x - cur >= k){ //长度为k的砖块剩余数量不为0,且这一层剩余长度大于这个长度k
cout<<cur<<' '<<i - 1<<' '<<cur + k<<' '<<i<<endl;
cur += k;
a[k] -- ;
if(cur == x) break;
}
}
}
}
return 0;
}
K NIO’s Sword
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 10;
int n;
int ans;
int pool[10];
signed main()
{
cin>>n;
pool[0] = 1;
for(int i = 1; i < 10; i ++ ) pool[i] = pool[i - 1] * 10;
if(n == 1){
puts("0");
return 0;
}
//并不需要真的找出具体方案,只需要判断哪个区间内有这个值就可以
//x是任意的,且x的变化不算在步数内,因此只要找到范围即可
for(int i = 1; i <= n; i ++ ){
for(int j = 1; j <= 7; j ++ ){
int l = (i - 1) * pool[j], r = i * pool[j] - 1; //注意左右边界
if(r - l + 1 >= n){
ans += j;
break; //这个步数已经找到,直接开始匹配下一个i
}
r %= n;
l %= n;
if(r > l){
if(i % n >= l && i % n <= r){ //余数在这个范围,说明只需要变换x就能找到同余的数
ans += j;
break; //这个步数已经找到,直接开始匹配下一个i
}
}
else{
if(i % n <= r || i % n >= l){ //i%n的余数在这个范围之内,说明还是可以构造出来
ans += j;
break; //这个步数已经找到,直接开始匹配下一个i
}
}
}
}
cout<<ans<<endl;
return 0;
}
N Particle Arts
比赛是想出思路了,但是竟然莫名其妙过不去,可能是因为1e5n的n三次方爆了,但是long long明明可以存下这么多,我不理解
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define db double
const int N = 1e5 + 10;
int n;
int a[N];
int cnt[20]; //记录第i位有几个1,从右往左排n~1
int get_wei(int x){
int res = 0;
while(x){
res ++ ;
x >>= 1;
}
return res;
}
int get_er(int x, int y){ //x这个数有y位二进制数
int res = 0;
for(int i = 1; i <= y; i ++ ){
if(x & 1){
res ++ ;
cnt[i] ++ ;
}
x >>= 1;
}
return res;
}
int tui(int iu){ //填充1
int res = 0;
for(int i = iu; i >= 1; i -- ){
if(cnt[i]){
res ++ ;
cnt[i] -- ;
}
res <<= 1;
}
res >>= 1;
return res;
}
int gcd(int a, int b){
if(b) return gcd(b, a % b);
else return a;
}
int li; //记录1的个数
int iu; //最高位有几位
int sum; //计算数值和
int ans1, ans2;
int sut;
signed main()
{
cin>>n;
for(int i = 0; i < n; i ++ ){
scanf("%lld", &a[i]);
sum += a[i];
int r = get_wei(a[i]);
iu = max(iu, r); //记录最高位数
li += get_er(a[i], r); //累加1的个数
}
//sum已记录
for(int i = 0; i < n; i ++ ){ //填充n个数
int t = tui(iu);
ans1 += t * t;
sut += sum * t;
}
ans1 *= n;
ans1 += sum * sum;
ans1 -= 2 * sut;
ans2 = n * n;
int ou = gcd(ans1, ans2);
if(ou > 1){
ans1 /= ou;
ans2 /= ou;
}
//最小公倍数*最大公约数=a*b
//最小公倍数=ans1*n/最大公约数
if(ans1 == 0) cout<<"0/1"<<endl;
else cout<<ans1<<"/"<<ans2<<endl;
return 0;
}