SMU Autumn 2024 Contest Round 14
2024.11.23 12:30————17:30
过题数7/13
补题数7/13
- Gifts in box
- BIT Palindrome
- Combination
- ZYW with BIT
- Equal
- ZYW with books
- Get off work
- Happiness Index
- String
- Stones
- ZYW with tutors
- Fake Travelling Salesman Problem
- Counting in Tree
[A - Gifts in box]
题解:
一个长n,宽m,高h的纸箱子里有一些长宽高均为1的礼物,现在以h为高从顶部看下去看到的礼物数字以一个nm的序列给出。将纸箱子翻倒,以n作为高,请输出从顶部往下看的礼物分布,以hm的序列输出。
根据样例可以想象,礼物会分布在上半部分,这一列上有礼物的行都会堆叠一个,以此往下方堆叠。
代码:
#include <iostream>
#include <set>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<string.h>
#include<map>
#include<math.h>
using namespace std;
#define int long long
int n,m,h;
int a[110][110];
int b[110][110];
void solve(){
cin >> n >> m >> h;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) cin >> a[i][j];
}
for (int i = 1; i <= h; i++) {
for (int j = 1; j <= m; j++) {
int res = 0;
for (int p = 1; p <= n; p++) {
if(a[p][j] > 0) res++;
a[p][j]--;
}
b[i][j] = res;
cout << b[i][j] << ' ';
}cout << endl;
}
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t = 1;
// cin>>t;
while(t--){
solve();
}
return 0;
}
[B - BIT Palindrome]
刚读完题就跑去博弈论了,从这题开始就没参与讨论。
题解:
给定一个数字n,要求返还有多少个满足条件的字符串,字符串刚好包含一个回文子串并且仅仅由b,i,t三个字母组成。
找规律。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e3+10;
const int p=1e9+7;
int n, m;
void solve(){
cin>>n;
if(n==1) cout<<0<<endl;
else if(n==2) cout<<3<<endl;
else if(n==3) cout<<18<<endl;
else {
cout<<6*(n+1)%p<<endl;
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}
[D - ZYW with BIT]
题意非常复杂,听了俩三遍,思路比较简单,但是代码冗长,我只做了一点纠错小工作,持续学习SG中,傅姐图论太厉害啦!
题解:
把等待时间当作点权,最短路的变形题。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int,int >
const int maxn=1e15;
const int N=510;
int n,m,T;
int w[N][N];
int ti[N][N];
int an[N];
int st[N];
int aaa[N];
vector<int>a[N];
void dj(int x,int y){
for(int i=0;i<=n;i++) an[i]=maxn,st[i]=0;
an[x]=y;
priority_queue<PII,vector<PII>,greater<PII> >q;
q.push({y,x});
while(q.size()){
auto [x1,y1]=q.top();
q.pop();
if(st[y1]) continue;
st[y1]=1;
int tim=ti[y1][x1%T]-1+x1;
for(int i=0;i<a[y1].size();i++){
if(tim+w[y1][a[y1][i]]<an[a[y1][i]]) {
an[a[y1][i]]=tim+w[y1][a[y1][i]];
q.push({an[a[y1][i]],a[y1][i]});
}
}
}
}
void chu(){
for(int i=1;i<=n;i++){
int k=0;
int time=1;
int cnt=-1;
bool flag=0;
for(int j=0;j<T;j++){
if(ti[i][j]){
if(cnt==-1)cnt=j;
for(int p=k;p<=j;p++){
ti[i][p]=time;
time--;
}
k=j+1;
flag=0;
}
else{
if(!flag) k=j,flag=1;
}
time++;
}
if(cnt==-1) {
for(int j=0;j<T;j++){
ti[i][j]=maxn;
}
}
else{
if(k!=0){
int cn=T-k+cnt+1;
for(int p=k;p<T;p++){
ti[i][p]=cn--;
}
}
}
}
}
void solve(){
cin>>n>>m>>T;
for(int i=1;i<=n;i++){
string s;
cin>>s;
for(int j=0;j<T;j++){
ti[i][j]=s[j]-'0';
}
}
for(int i=0;i<m;i++){
int x,y,ww;
cin>>x>>y>>ww;
w[x][y]=ww;
w[y][x]=ww;
a[x].push_back(y);
a[y].push_back(x);
}
chu();
// for(int i=1;i<=n;i++){
// for(int j=0;j<T;j++){
// cout<<ti[i][j]<<" ";
// }
// cout<<endl;
// }
for(int i=0;i<T;i++){
// cout<<i+ti[1][i]-1<<" ";
dj(1,i);
aaa[i]=an[n]-an[1];
}
for(int i=0;i<T;i++){
cout<<aaa[i]<<" ";
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T=1;
// cin>>T;
while(T--){
solve();
}
return 0;
}
//
//10 3
//1 2
//2 3
//3 4
//4 5
//5 6
//6 7
//7 8
//8 9
//9 10
[E - Equal]
题解:
签到题。给定俩个数字x和y,可以进行俩个操作,x+1或y+2,用最少的操作次数让俩个数相等。
代码:
#include <iostream>
#include <set>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<string.h>
#include<map>
#include<math.h>
using namespace std;
#define int long long
int x,y;
void solve(){
cin >> x >> y;
if(x <= y) cout << y-x;
else {
int ls = x-y;
if(ls%2 ==0 ) cout << ls/2;
else cout << ls/2+2;
}
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t = 1;
// cin>>t;
while(t--){
solve();
}
return 0;
}
[G - Get off work]
还是傅姐的图论,廷哥and me持续学习SG中…傅姐带飞直接
题解:
n个员工,每辆车最多可以做k个人,给定连接关系,问需要多少辆车才能把所有员工送回家,车辆不回头。
反向思维,把所有员工从家送回来,所以每个叶子节点都至少需要一辆车。往公司送的同时计算此时这个点处能接送几个人,如果接送不了这个人,加一辆车。
代码:
#include <iostream>
#include <set>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<string.h>
#include<map>
#include<math.h>
using namespace std;
#define int long long
int n,k;
const int N = 2e5+10;
vector<int>a[N];
int st[N];
int ans;
void dfs(int x,int fa) {
if(a[x].size() == 1 && x != 1) st[x]=k,ans++;
for (int i = 0; i < a[x].size(); i++) {
if(a[x][i]==fa)continue;
dfs(a[x][i],x);
st[x] += (st[a[x][i]]-1);
}
if(st[x] < 1 && x != 1) ans++,st[x] = k;
}
void solve(){
ans = 0;
cin >> n >> k;
for (int i = 0;i <= n+1; i++) a[i].clear(),st[i] = 0;
for (int i = 1; i < n; i++) {
int u,v;
cin >> u >> v;
a[u].push_back(v);
a[v].push_back(u);
}dfs(1,0);
cout << ans << endl;
return ;
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t = 1;
cin>>t;
while(t--){
solve();
}
return 0;
}
[J - Stones]
哦贯穿始终的博弈论啊,最后还是廷哥一点一点改出来的,主打一个啥也不懂但能造样例。
题解:
n堆石子,Alice先手拿,每次可以拿一堆石子的1到(数量+1)/2颗,谁先拿不了谁就输。
没有什么技巧真的硬试出来的,服气。
注意map底部逻辑是红黑树,如果tle可以考虑换一种方式。
代码:
#include <iostream>
#include <set>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<string.h>
#include<map>
#include<math.h>
using namespace std;
const int N=1e6+10;
int n;
int a[N];
int pass[30]={0,2,6,14,30,62,126,254,510,1022,2046,4094,8190,16382,32766,65534,131070,262142,524286,1048574,2097150,4194302,8388606,16777214,33554430,67108862,134217726,268435454,536870910,1073741822};
int sg(int num){
for(int j=0;j<30;++j) if(num==pass[j]){return 0;}
if(num&1) return num-(num+1)/2+1;
else{
return sg(num/2-1);
}
}
void solve(){
int x = 2;
cin >> n;
int res = 0;
bool flag = 1;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
if(a[i] == 0) continue;
flag = 0;
for(int j=0;j<30;++j) if(a[i]==pass[j]){flag=1; break;}
if(flag) continue;
res = res xor (sg(a[i]));
} //cout << res << endl;
if(res) cout << "Alice";
else cout << "Bob";
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t = 1;
// cin>>t;
while(t--){
solve();
}
return 0;
}
[K - ZYW with tutors]
签到吧,不过不是我签的。
题解:
给出一个行列式,可以更改一个数字使得行列式的值最小。
由于当行列式的左上——右下对角线上有数字0时,行列式的值也是数字0,所以输出0即可。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e3+10;
int n, m;
int a[N][N];
void solve(){
cin>>n;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>a[i][j];
}
}
cout<<0<<endl;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T=1;
// cin>>T;
while(T--){
solve();
}
return 0;
}