2024.11.20组队训练记录
B . osu!mania
题面:
\(
pp = \max\left(0, \frac{320a + 300b + 200c + 100d + 50e + 0f}{320(a + b + c + d + e + f)} - 80\% \right) \times 5 \times ppmax
\)
输入:
输入的第一行包含一个正整数 $ T $ ,表示数据组数。保证 $ 1 \leq T \leq 100 $ 。
对于每组测试数据:
输入的第一行包含一个非负整数 $ ppmax $。保证 $ 0 \leq ppmax \leq 3000 $。
输入的第二行包含六个非负整数 $ a, b, c, d, e, f $,含义如题目描述所示。保证 $ 0 \leq a, b, c, d, e, f \leq 2 \times 10^4 $ 且 $ a+b+c+d+e+f \geq 1 $。
输出:
对于每组测试数据:输出一行两个数,以空格隔开。其中第一个数表示准确率,以百分数形式输出,精确到 \(10^{-4}\);第二个数为个人表现,以整数形式输出。
样例:
2
630
3029 2336 377 41 10 61
3000
20000 10000 0 0 0 0
————————
96.20% 423
100.00% 2688
思路:就是按公式计算,这里要四舍五入,这里采用除数乘回答案和除数乘(答案+1),然后用差值绝对值谁最小就靠近谁,这样就避免了精度损失
#include<bits/stdc++.h>
#define test(i) cout << #i << " "<< i << " " << endl;
#define endl '\n'
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int N=2e5+5;
ll t,n;
void fio(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
void print(double a1,ll a2){
a1*=100;
printf("%.2lf",a1);
cout << "%" << " ";
printf("%lld",a2);
cout << endl;
}
void solve(){
double pp;
cin >> pp;
long double a[10],b[]={300,300,200,100,50,0};
ll c[]={320,300,200,100,50,0};
for(int i=0; i<6; i++){
cin >> a[i];
}
double ans1=0;
ll ans2=0;
double tmp=0;
for(int i=0; i<6; i++){
ans1+=a[i]*b[i];
tmp+=a[i];
}
ans1/=tmp*300;
for(int i=0; i<6; i++){
ans2+=a[i]*c[i];
}
ans2-=256*tmp;
ans2=ans2*5*pp;
if(ans2<0) print(ans1,0);
else{
ll tt=ans2;
tt/=320*tmp;
ll t1=tt,t2=tt+1;
if(llabs(t1*320*tmp-ans2)>=llabs(t2*320*tmp-ans2)) print(ans1,t2);
else print(ans1,t1);
}
}
signed main()
{
//fio();
cin >> t;
//t=1;
while(t--){
solve();
}
return 0;
}
C.连方
题面:
给定正整数 $ n $ 和两个仅包含字符 .
和 #
的长度为 $ n $ 的字符串 $ a, b $,请构造一个 $ 7 \times n $ 的仅包含字符 .
与 #
的矩阵,满足以下条件:
- 矩阵第 1 行与 $ a $ 相同,第 7 行与 $b $相同。
- 由四方向连通的
#
构成的图形均为实心的矩形。具体地:- 对于两个
#
字符,如果可以从其中一个#
字符出发,在有限步之内仅经过#
字符到达另一个#
字符,其中每一步均为向上、左、下、右四个方向之一移动一格,则称这两个#
字符在同一组。那么,由同一组内的所有#
字符构成的图形均为实心的矩形。
- 对于两个
- 所有的
#
字符八方向连通,具体地:- 对于任意两个
#
字符,均可以从其中一个#
字符出发,在有限步之内仅经过#
字符到达另一个#
字符,其中每一步均为向上、左、下、右、左上、右上、左下、右下八个方向之一移动一格。
- 对于任意两个
请输出任意一个满足条件的矩阵,或判定无解。
输入:
从标准输入读入数据。
输入的第一行包含一个正整数 $ T (1 \leq T \leq 10^4) $,代表数据组数。
每组数据第一行包含一个正整数 $ n (2 \leq n \leq 10^5) $,代表矩阵的宽度。
接下来两行分别包含仅包含字符 .
与 #
,长度为 $ n $ 的两个字符串 $ a, b $,代表矩阵的第 1 行与第 7 行。
保证 $ a $与 $ b $均包含至少一个 #
。
保证单个测试点内所有$ n$ 的总和不超过$ 2 \times 10^5$。
输出:
输出到标准输出。
对于每组测试数据,如果不存在满足要求的矩阵,则输出一行一个字符串 No。
如果存在满足要求的矩阵,则先输出一行一个字符串 Yes,然后输出 7 行,每行包
含一个长度为 n 的字符串,代表你构造的矩阵。
思路:本题构造思路不难,对于列大于等于2后,只要一个字符串全为#,另一个字符串有.且有#则一定无解。
特判列为1时情况,然后对列大于等于2以后再满足基本情况下(字符串#如果旁边是. 就在.附近构造#)就是考虑构造一条通路即可。不难写,但是分类多。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int x[10][100005]={0};
void solve(){
int n;
scanf("%d",&n);
string a;
string b;
cin>>a>>b;
int jd1=0,jd11=0;
int jd2=0,jd22=0;
int st1=0,st2=0;
for(int i=1;i<=7;i++){
for(int j=1;j<=n;j++){
x[i][j]=0;
}
}
for(int i=0;i<n;i++){
if(a[i]=='.'){
jd1=1;
if(st1==0&&i>0)st1=i+1;
x[1][i+1]=0;
}else{
jd11=1;
x[1][i+1]=1;
}
}
for(int i=0;i<n;i++){
if(b[i]=='.'){
jd2=1;
if(st2==0&&i>0)st2=i+1;
x[7][i+1]=0;
}else{
jd22=1;
x[7][i+1]=1;
}
}
if(jd1==1&&jd11==1&&jd2==0){
printf("No\n");
return ;
}
if(jd1==0&&jd22==1&&jd2==1){
printf("No\n");
return ;
}
printf("Yes\n");
if(jd11==0&&jd2==0){
cout<<a<<"\n";
for(int i=2;i<=7;i++){
for(int j=1;j<=n;j++){
printf("#");
}
printf("\n");
}
return ;
}
if(jd1==0&&jd22==0){
for(int i=1;i<=6;i++){
for(int j=1;j<=n;j++){
printf("#");
}
printf("\n");
}
cout<<b<<"\n";
return ;
}
if(jd1==0&&jd2==0){
for(int i=1;i<=7;i++){
for(int j=1;j<=n;j++){
printf("#");
}
printf("\n");
}
return ;
}
for(int i=2;i<=n;i++){
if(a[i-1]=='.'){
x[2][i]=1;
}
}
for(int i=2;i<st1;i++){
x[3][i]=1;
}
if(st1==2){
x[3][1]=1;
}else if(st1<=1){
x[3][1]=1;x[2][1]=1;
}
if(st2==2){
x[5][1]=1;
}else if(st2<=1){
x[6][1]=1;x[5][1]=1;
}
x[4][1]=1;
for(int i=2;i<=n;i++){
if(b[i-1]=='.'){
x[6][i]=1;
}
}
for(int i=2;i<st2;i++){
x[5][i]=1;
}
cout<<a<<"\n";
for(int i=2;i<=6;i++){
for(int j=1;j<=n;j++){
if(x[i][j]==1){
printf("#");
}else{
printf(".");
}
}
printf("\n");
}
cout<<b<<"\n";
return ;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
solve();
}
return 0;
}
E.合成大西瓜
题面:
小白有 $ n $ 个西瓜(保证 $ n $是奇数),每个西瓜有个重量 $ a_i $。她在这 $n $ 个西瓜之间建立了 $ m $ 条无向边,使任意两个西瓜之间都至少存在一条路径能到达。
小白现在可以选择三个西瓜进行合并,具体地,她会选择三个不同的西瓜$ x, y, z $ 满足$ x, y $ 之间有一条无向边\(y,z\)之间有一条无向边。她会得到一个新的西瓜 $ w$ ,其重量\(a_w\)= $max(a_y, \min(a_x, a_z)) $。接下来,她对于“至少和 $ x, y, z $ 中某个西瓜之间有无向边”的西瓜 $ t $,建立了一条 $(w, t) $ 之间的无向边。最后,小白删去了 $ x, y, z$ 三个西瓜以及某一端为 $ x, y, z$的无向边。
可以证明一定存在一种合并 $\frac{n-1}{2} $ 次的方案使得最后仅剩下一个西瓜,小白想知道最后那个西瓜重量的最大值是多少。
输入:
从标准输入读入数据。
第一行两个非负整数 $ n, m $。保证 $ 1 \leq n \leq 10^5, 0 \leq m \leq 10^5 $,且 $n $ 是奇数。
第二行 $ n $ 个正整数$a_1, a_2, \ldots, a_n $,表示每个西瓜的重量。保证 $ 1 \leq a_i \leq n $。
接下来$ m $ 行,每行两个正整数 $ x, y $ 表示图上的一条无向边 $ (x, y) $。保证 $ 1 \leq x, y \leq n $ 且 $x \neq y $。
保证给定的无向图连通,且无重边与自环。
输出:
输出到标准输出。
一行一个正整数,表示答案。
样例:
7 7
1123121
1 2
2 3
1 3
2 4
2 5
5 6
5 7
————
2
。
1 0
—————
1
思路:对于读度大于等于2的点,他一定可以成为最后三点的中心点。对于度为1的点他只能成为最后三点的外点,所以最后在度为二的点的最大值和度为1的点的的第二大值取个max即可。特判一节点情况
#include<bits/stdc++.h>
#define test(i) cout << #i << " "<< i << " " << endl;
#define endl '\n'
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int N=2e5+5;
ll t;
ll w[N],in[N];
vector<ll> G[N],V[N];
void fio(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
void solve(){
ll n,m,u,v;
cin >> n >> m;
for(int i=1; i<=n; i++)cin >> w[i];
if(n==1){
cout << w[1] << endl;
return;
}
for(int i=1; i<=m; i++){
cin >> u >> v;
in[u]++;
in[v]++;
G[v].push_back(u);
G[u].push_back(v);
}
ll ans=0;
ll fir=0,sec=0;
for(int i=1; i<=n; i++){
if(in[i]<2){
if(fir<=w[i]){
sec=fir;
fir=w[i];
}
else if(sec<=w[i]){
sec=w[i];
}
continue;
}
ans=max(ans,w[i]);
}
ans=max(ans,sec);
cout << ans << endl;
}
signed main()
{
//fio();
//cin >> t;
t=1;
while(t--){
solve();
}
return 0;
}
I.算术
题面:
Menji学习了加法和乘法。
Menji有一些写着 \(1\sim 9\) 的卡片,其中写着 \(i\) 的有 \(a_i\) 张。
Menji每次会选择两张卡片,并选择将他们的和或者他们的积写在一张新的卡片上,之后他会丢弃选择的两张卡片,并拿起新的一张卡片。
可以发现,经过 \(\left(\sum_{i=1}^{9} a_i\right)-1\) 轮操作之后,Menji手上只剩下一张卡片,Menji想要最大化这张卡片上数字的值,但由于卡片数量太少,Menji无法独立完成这个任务,希望你能帮他求出最后的数字最大能是多少。
由于本题答案很大,你只需要输出答案对 998244353 取模后的值。注意,你需要输出的是最大值 mod 998244353,而不是 mod 998244353 意义下的最大值。
输入:
从标准输入读入数据。
本题含有多组测试数据。第一行一个正整数 $ T (1 \leq T \leq 1000) $,表示数据组数。
之后 $ T $ 行,每行 9 个非负整数 $ a_1, a_2, \ldots, a_9 (0 \leq a_i \leq 100, \sum_{i=1}^9 a_i \geq 1) $。
输出:
输出 T 行,其中第 i 行是第 i 组数据中最终剩余的数的最大值对 998244353 取模
的结果。
7
5 3 0 0 0 0 0 0 0
4 1 1 1 0 0 0 0 0
1 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 2
99 88 77 66 55 44 33 22 11
8 100 90 80 70 60 50 40 30 20
————————
54
108
1
10
90
90553232
143532368
思路:
本题可以先通过样例得到,当有1时最好先把2转成3,如果1还有剩余就把他自己给合成为2,然后再耗费1进行2变3操作.如果最后1还有剩余,就遍历下3到9看看能否加1,如果可以加1就加上,最后用快速幂计算(2~10)答案值。如果还剩了1就直接最后答案++就行了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
ll qm(ll a,ll x){
ll ans=1;
while(x){
if(x%2){
ans=(ans%mod)*(a%mod)%mod;
}
a=(a%mod)*(a%mod)%mod;
x/=2;
}
return ans%mod;
}
ll a[100]={0};
void solve(){
for(int i=1;i<=9;i++) scanf("%lld",&a[i]);
int jd=0;
for(int i=2;i<=9;i++){
if(a[i]>0){
jd=2;
}
}
if(a[1]>1){
jd=2;
}
a[10]=0;
while(a[1]>1){
if(a[2]>1){
a[2]-=2;a[3]+=2;
a[1]-=2;
}else{
a[1]-=2;
a[2]++;
}
}
for(int i=2;i<=9&&a[1]>0;i++){
if(a[i]>0){
a[i]--;
a[i+1]++;
a[1]=0;
break;
}
}
ll ans=1;
for(ll i=2;i<=10;i++){
ll tem=qm(i,a[i]);
ans=(ans%mod)*(tem%mod)%mod;
}
if(jd==2&&a[1]==1){
ans++;
}
ans%=mod;
printf("%lld\n",ans);
}
int main(){
int t;
scanf("%d",&t);
while(t--){
solve();
}
return 0;
}
J . 骰子
这里图我没粘到,偷个懒,直接截图
题面:
输入:
从标准输入读入数据。
输入一行两个整数$ n, m (2 ≤ n, m ≤ {10^3})$,表示网格的长和宽
输出:
输出一行一个整数,表示在进行任意多次操作后,网格上所有写过数字的格子的数
字的和的最大值。
样例:
2 2
输出
24
思路:显然n>=2且m>=2,且题目样例答案为24.可以把这个\(2*2\),图视作任意给出的图的子图,显然具有一定的传递性,直接\(n*m*6\)
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
int main()
{
fio();
ll t;
t=1;
while(t--)
{
ll n,m;
cin>>n>>m;
cout<<n*m*6<<endl;
}
}
K.小 C 的神秘图形
题面:
对于正整数 $ n $,定义一个 $ 3^n \times 3^n $ 的 01 矩阵 $ A_n $:
- 若 $3^{n-1} \leq i < 2 \times 3^{n-1} $ 或者 $ 3^{n-1} \leq j < 2 \times 3^{n-1} $,则
$ A_n(i, j)$ = \(\left\{ \begin{array}{ll} 1, & n=1, \\ A_{n-1}(i \mod 3^{n-1}, j \mod 3^{n-1}), & n \geq 2. \end{array} \right.\)
其中 $ x \mod y $ 表示 $ x $ 对 $ y $ 取模后的结果。
- 否则,$ A_n(i, j) = 0 $。
给定正整数 $ n $,小 C 有两个长度为 $ n $ 的数字串,代表两个三进制数 $ n_1, n_2 $。需要求出 $ A_n(n_1, n_2) $ 的值。
输入:
第一行输入一个正整数 n(1 ≤ n ≤ 105),含义见题目描述。
接下来两行,每行输入一个长度为 n 的数字串,分别表示三进制数 n1, n2。
输出:
输出一个整数,表示 An(n1, n2) 的值。
样例:
2
20
01
——————
0
,
3
102
011
——————
1
思路:
这里从左到右看上下是否有个数字为1就行了,如果对于每个位置都有1,则输出1
否则输出0。具体证明方法不不知道,这个是由队友给出的。这里看看打表后的9*9矩阵位置值为1的x与y坐标的三进制应该可以得出这个推论。
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 3;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll a[40][40];
ll b[40][40];
int main()
{
fio();
ll t;
ll n;
cin>>n;
string f1,f2;
cin>>f1>>f2;
ll n1,n2;
ll pd=1;
for(ll i=0;i<n;i++)
{
if(f1[i]=='1'||f2[i]=='1')
{
continue;
}
else
pd=0;
}
if(pd)
cout<<1<<endl;
else cout<<0<<endl;
}