姓名:徐浩轩,校区:和谐校区,考试时间: 2024 2024 2024 年 10 10 10月 3 3 3日 09 : 00 : 00 09:00:00 09:00:00- 12 : 30 : 00 12:30:00 12:30:00,学号: S 08503 S08503 S08503
CSP-J Day 3 3 3 模拟赛补题报告
前言
考了我们班第10(QAQ~~比上次降了7位)
T1 ip:
A
c
c
e
p
e
t
e
d
100
\color{green}Accepeted\space100
Accepeted 100
T2 same:
W
r
o
n
g
_
a
n
s
w
e
r
30
\color{red}Wrong\_answer\space30
Wrong_answer 30
T3 box:
W
r
o
n
g
_
a
n
s
w
e
r
10
\color{red}Wrong\_answer\space10
Wrong_answer 10
T4 party:
W
r
o
n
g
_
a
n
s
w
e
r
40
\color{red}Wrong\_answer\space40
Wrong_answer 40
T1
题面
我们有 N 个设备,每个设备都有它的名称和IPv4地址,现在我们有 Q 个问题,每次我们想知道给出的IPv4地址是哪一个设备?
思路
将名称为k的IPv4地址存下来,看看对应问题中的哪一个即可
代码
#include<bits/stdc++.h>
using namespace std;
map<string,string> mp;
int n,m;
string s,t;
int main(){
cin>>n;
for(int i=1;i<=n;++i){
cin>>s>>t;
mp[t]=s;
}
cin>>m;
for(int i=1;i<=m;++i){
cin>>t;
cout<<mp[t]<<"\n";
}
return 0;
}
T2
题面
有两个长度为 N 的数组 a,b,我们想知道数组 a 和数组 b 是否是同构数组?
我们定义两个数组 a,b 同构,则存在一个整数 k,使得 0 <= k <= n / 2,有保持数组 b 不动的时候,交换数组 a 的前 k 项和后 k 项位置,使得新的数组 a 完全相等于数组 b。
思路
先看看位于前半部分的a[1],所对应的b[1]是否位于后半部分,如果不是,直接输出no,如果是,看看将a所对应的b交换过来后是否能让数组相等即可
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int t,n,a[N],b[N];
bool check(){
for(int i=1;i<=n;++i){
if(a[i]!=b[i]){
return false;
}
}
return true;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=n;++i){
cin>>a[i];
}
for(int i=1;i<=n;++i){
cin>>b[i];
}
if(check()){
cout<<"Yes\n";
continue;
}
int pos=(n>>1)+1;
for(;pos<=n;pos++){
if(a[pos]==b[1]){
break;
}
}
for(int i=pos;i<=n;i++){
swap(a[i],a[i-pos+1]);
}
if(check()){
cout<<"Yes\n";
}
else{
cout<<"No\n";
}
}
return 0;
}
T3
题意
我们有 N 个箱子,每个箱子有自己的重量 w[i],每次我们可以将至多 M 个箱子合并成一个重量为这几个箱子重量和的箱子,花费的体力是这合并的几个箱子的重量和。请问我们将这所有的箱子合并成一个箱子所需要花费的最少体力是多少?
思路
可以想到,每次合并最小的箱子是最优的,因此不断合并最小的 个箱子后,重新排序得到新序列,然后继续合并最小的m个箱子。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,x;
priority_queue<int,vector<int>,greater<int> > pq;
signed main(){
cin>>n>>m;
for(int i=1;i<=n;++i){
cin>>x;
pq.push(x);
}
if((n-1)%(m-1)>0){
int cnt=m-1-(n-1)%(m-1);
while(cnt--){
pq.push(0);
}
}
int ans=0;
while(pq.size()>1){
int res=0;
for(int j=1;j<=m;++j){
res+=pq.top();
pq.pop();
}
ans+=res;
pq.push(res);
}
cout<<ans;
return 0;
}
T4
题意
有 N 个患有社交恐惧症的人想参与一个聚会,但是这个聚会只有两张桌子,这些社恐们不想跟自己不认识的人坐在一起!你是这次聚会的主办方,请你想想办法,看看能不能将这 N 个人分在两张桌子,使得每张桌子的任意两个人都是相互认识的。如果你有办法让这 N 个人分在两张桌子,请你再想想办法看看能不能让这两张桌子中人数最多的一张桌子的入座人数最少呢?
思路
我们把所有不互相认识的人之间连一条无向边,然后我们可以对于所有连通块判断当前连通块是否是二分图(使用黑白染色法),如果不是二分图,则直接输出 NO ,否则我们可以记录一下每个连通块中黑点的数量和白点的数量(代表在第一张桌子还是第二张桌子)。注意,黑点和白点本质没有任何区别,我们每个连通块都可以黑白互换。然后我们求得每个连通块的黑点和白点数量后,我们可以做一遍判定性背包dp来求解答案。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=514;
int n,m,cnt,a[N][N],sz[N][2],col[N];
bool f[N],vis[N];
bool dfs(int u,int c){
vis[u]=1,col[u]=c,sz[cnt][c]++;
for(int i=1;i<=n;++i){
if(i!=u&&(!a[i][u]||!a[u][i])){
if(vis[i]){
if(col[u]==col[i]){
return false;
}
}
else if(!dfs(i,1-c)){
return false;
}
}
}
return true;
}
int main(){
cin>>n;
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
cin>>a[i][j];
}
}
for(int i=1;i<=n;++i){
if(!vis[i]){
cnt++;
if(!dfs(i,0)){
printf("No\n");
return 0;
}
}
}
m=n>>1;
f[0]=1;
for(int i=1;i<=cnt;++i){
for(int j=m;;j--){
if(j<sz[i][0]&&j<sz[i][1]){
break;
}
if(j>=sz[i][0]){
f[j]|=f[j-sz[i][0]];
}
if(j>=sz[i][1]){
f[j]|=f[j-sz[i][1]];
}
}
}
for(int j=m;j>=1;--j){
if(f[j]){
printf("Yes\n%d",n-j);
break;
}
}
return 0;
}