西南民族大学 2024 天梯选拔赛(二)
西南民族大学 2024 天梯选拔赛(二)
L1-1
查看代码
void solve() {
cout<<"yuan shen, qi dong!";
}
L1-2
思路:化简比较
查看代码
void solve() {
double n;
cin>>n;
double b=1/n;
if(fabs(n-b)<eps)cout<<"=";
else if(n<b)cout<<"<";
else cout<<">";
}
L1-3
查看代码
void solve() {
double x;
cin>>x;
double ans;
if(x<9)ans=2;
else {
ans=1+8/x;
}
cout<<fixed<<setprecision(2)<<ans;
}
L1-4
思路:注意读题
查看代码
void solve() {
double a,b,c,d;
cin>>a>>b>>c>>d;
auto P=[](double a,double b){
double res=(a+b)/2;
if(fabs(a-0.0)<eps||fabs(b-0.0)<eps)res/=2;
else if(fabs(a-2.0)<eps&&fabs(b-2.0)<eps)res*=2;
return res;
};
double ans=(P(a,b)+P(c,d))/2;
cout<<fixed<<setprecision(6)<<ans;
}
L1-5
思路:仔细读题
路径已经给定了,便可以求出路径长度。一个灯源能扩散到的范围是2*(15-m)+1,求最少需要灯源即可
查看代码
void solve() {
int n,m;
cin>>n>>m;
int sum=1;
vector<PII>ve(n);
for(int i=0;i<n;++i){
cin>>ve[i].first>>ve[i].second;
if(i)sum+=abs(ve[i].first-ve[i-1].first)+abs(ve[i].second-ve[i-1].second);
}
if(m==0)cout<<0;
else{
int cnt=(15-m)*2+1;
cout<<(sum+cnt-1)/cnt;
}
}
L1-6
思路:代码内容为第一个main到最后一个return
查看代码
void solve() {
int n;
cin>>n;
string s;
cin>>s;
string t;
cin>>t;
auto a=t.find("main"),b=t.rfind("return");
if(a==-1||b==-1){
cout<<"wrong";
return ;
}
b+=5;
for(int i=2;i<t.size();++i){
if(i-2>=a&&i<=b)continue;
// if(i<a||i-2>b){
if(t[i-2]==s[0]&&t[i-1]==s[1]&&t[i]==s[2]){
t[i-2]='z',t[i-1]='x',t[i]='z';
}
// }
}
cout<<t;
}
L1-7
思路:贪心
分成m段连续数相当于取出m-1个差值,那就贪心取最大的
查看代码
void solve() {
int n,m,ans=0;
cin>>n>>m;
vector<int>a(n),g;
for(int i=0;i<n;++i){
cin>>a[i];
if(i){
g.push_back(a[i]-a[i-1]);
}
}
sort(g.begin(),g.end(),greater<int>());
ans=a[n-1]-a[0];
for(int i=0;i<m-1;++i)ans-=g[i];
cout<<ans;
}
L1-8
思路:其实求的是异或和,用前缀异或和求
查看代码
void solve() {
int n;
cin>>n;
vector<int>ve(n+1);
for(int i=1;i<=n;++i){
cin>>ve[i];
ve[i]^=ve[i-1];
}
int m;
cin>>m;
while(m--){
int l,r;
cin>>l>>r;
int ans=ve[r]^ve[l-1];
cout<<ans<<'\n';
}
}
L2-1
思路:模拟啦
查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e5+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
void solve() {
int n,k;
cin>>n>>k;
vector<int>a(n);
queue<int>q;
stack<int>s,now;
for(int i=0;i<n;++i){
cin>>a[i];
}
for(int i=n-1;i>=0;--i)q.push(a[i]);
vector<vector<int>>ve;
vector<int>t;
while(1){
if(q.empty()) {
if (now.size() >= 2) {
vector<int>f;
while(now.size()){
f.push_back(now.top());
now.pop();
}
ve.push_back(f);
} else if (now.size() == 1) {
t.push_back(now.top());
now.pop();
}
if (!s.empty()) {
while(s.size()){
q.push(s.top());
s.pop();
}
} else {
break;
}
}
int u=q.front();
q.pop();
if(now.empty())now.push(u);
else{
if(u>now.top()&&u-now.top()<=k){
now.push(u);
}else{
if(s.empty()){
s.push(u);
}else{
if(s.top()>now.top()&&s.top()-now.top()<=k){
now.push(s.top());
s.pop();
}
s.push(u);
}
}
}
}
for(auto v:ve){
for(auto u:v)cout<<u<<' ';
cout<<'\n';
}
for(auto v:t)cout<<v<<' ';
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
// cin>>t;
// init();
while(t--){
solve();
}
return 0;
}
L2-2
思路:dfs
由于每种材料的等级最高100,枚举所有等级花费即可。然后就是dfs跑需要的合成材料
查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e5+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
int x,m;
vector<int>id(N);
vector lev(3,vector<int>(105,0));
vector<PII>ve[N];
int dfs(int u){
// if(ve[u].empty())return 0;
int sum=0;
for(auto [v,d]:ve[u]){
if(!ve[v].empty())sum+=dfs(v);
sum+=lev[id[v]][d];
}
return sum;
}
void solve() {
cin>>x>>m;
for(int i=0;i<m;++i){
int a,b,c,d;
cin>>a>>b>>c>>d;
ve[a].push_back({b,d});
id[b]=c-1;
}
lev[0][2]=1;
for(int i=3,p=1;i<=100;++i,p++){
lev[0][i]=lev[0][i-1]+p;
}
lev[1][2]=1;
for(int i=3,p=2;i<=100;++i,p+=2){
lev[1][i]=lev[1][i-1]+p;
}
lev[2][2]=1;
for(int i=3,p=5;i<=100;++i,p+=5){
lev[2][i]=lev[2][i-1]+p;
}
int ans=dfs(x);
cout<<ans;
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
// cin>>t;
// init();
while(t--){
solve();
}
return 0;
}
L2-3
思路:由于最多9位,考虑从数的状态求贡献。对于Si+Sj中的分割线可以在Si或Sj,那分别枚举每个数在Si和Sj的贡献。若一个数在Si,那就考虑所有分界线的情况(最多9种,因为最多9位),知道了分界线就可以求出另一半的各个位数之和,这里预处理出所有各个位数之和的个数,直接统计贡献即可。在Sj同理。还有一个条件是长度为偶数,那就把所有数按长度奇偶分类,统计贡献的时候只需要统计长度奇偶性相同的。
查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=5e5+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
void solve() {
int n;
cin>>n;
vector<string>ve(n);
vector<int>sum(n);
vector<vector<int>>g(2,vector<int>(100));
auto P=[](string s){
int c=0;
for(int i=0;i<s.size();++i)c+=s[i]-'0';
return c;
};
for(int i=0;i<n;++i){
cin>>ve[i];
int c=P(ve[i]);
g[ve[i].size()%2][c]++;
sum[i]=c;
}
int ans=0;
for(int i=0;i<n;++i){
string c=ve[i];
int p=c.size()%2;
int l=0;
for(int j=0;j<c.size();++j){
l+=c[j]-'0';
int r=sum[i]-l;
if(l>r)ans+=g[p][l-r];
}
int r=0;
for(int j=c.size()-1;j>0;--j){
r+=c[j]-'0';
l=sum[i]-r;
if(l<r)ans+=g[p][r-l];
}
}
cout<<ans;
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
// cin>>t;
// init();
while(t--){
solve();
}
return 0;
}
L2-4
思路:bfs+贪心
首先贪心的想,先遍历权值小的位置。如果遇到强化剂,那直接加上权值,并令其权值为0,所以用{权值,x,y}来存储,跑一遍bfs即可
查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e5+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
struct E{
int x,y,s;
bool operator<(const E&e)const{
return s>e.s;
}
};
void solve() {
int n,m,x,y,t;
cin>>n>>m>>x>>y>>t;
vector ve(n+1,vector<int>(m+1)),is(n+1,vector<int>(m+1)),st(n+1,vector<int>(m+1));
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)cin>>ve[i][j];
for(int i=0;i<t;++i){
int a,b;
cin>>a>>b;
is[a][b]=1;
}
priority_queue<E>q;
st[x][y]=1;
q.push({x,y,ve[x][y]});
int ans=0;
while(q.size()){
auto [xx,yy,d]=q.top();
q.pop();
if(d<=ans||(x==xx&&y==yy)){
ans+=d;
}else break;
for(int i=0;i<4;++i){
int x1=xx+dx[i],y1=yy+dy[i];
if(x1<0||x1>n||y1<0||y1>m||st[x1][y1])continue;
if(is[x1][y1]){
ans+=ve[x1][y1];
q.push({x1,y1,0});
}else q.push({x1,y1,ve[x1][y1]});
st[x1][y1]=1;
}
}
cout<<ans;
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
// cin>>t;
// init();
while(t--){
solve();
}
return 0;
}
L3-1
思路:dp
根据题目所求,首先用f[i][j]表示前i个数分成j组的最大值,且若选第i个数,第i个数为第j组的最后一个
若不选第i个数:f[i][j]=f[i-1][j]
若选第i个数:f[i][j]=max(f[i][j],f[i-m][j-1]+sum{i-m+1,i} )
这里用前缀和求区间和
求具体方案的话,考虑倒着取,选取最优情况一定是满足 f[i][j]=max(f[i][j],f[i-m][j-1]+sum{i-m+1,i} ) ,那就可以枚举i,找到所有组别的最后一个数
查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=5e5+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
void solve() {
int n,m,k;
cin>>n>>m>>k;
vector<int>p(n+1),pre(n+1);
for(int i=1;i<=n;++i){
cin>>p[i];
pre[i]=pre[i-1]+p[i];
}
vector<vector<int>>f(n+1,vector<int>(k+1));
for(int i=1;i<=n;++i){
for(int j=1;j<=k;++j){
f[i][j]=max(f[i][j],f[i-1][j]);//buxuan
if(i-m>=0){
f[i][j]=max(f[i][j],f[i-m][j-1]+(pre[i]-pre[i-m]));
}
}
}
cout<<f[n][k]<<'\n';
vector<PII>ans;
int t=k;
for(int i=n;i>=m&&t>0;t--){
while(t>0&&f[i][t]!=f[i-m][t-1]+pre[i]-pre[i-m]){
i--;
}
ans.push_back({i-m+1,i});
i-=m;
}
std::reverse(ans.begin(), ans.end());
for(auto [x,y]:ans)cout<<x<<' '<<y<<'\n';
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
// cin>>t;
// init();
while(t--){
solve();
}
return 0;
}
L3-2
思路:
dfs序(dfn)为是一棵树的每个节点在dfs中的进出栈的时间序列
将整棵树用dfn表示,相当在一维的序列上处理。一个节点的子树便可以由一段连续的dfn表示,相当于在一维序列上求区间和。修改的话找到该节点所在的dfn进行单点修改即可,用树状数组或线段树求
查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e6+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
int c[N],n,m;
int lowbit(int x){
return x&-x;
}
int getsum(int x){
int ans=0;
while(x>0){
ans+=c[x];
x-=lowbit(x);
}
return ans;
}
void add(int x,int k){
while(x<=n){
c[x]+=k;
x+= lowbit(x);
}
}
int get(int l,int r){
return getsum(r)-getsum(l-1);
}
vector<vector<int>>g;
vector<int>to,l,r;
int idx=0;
void dfs(int u){
to[u]=++idx;
l[u]=idx;
for(auto v:g[u]){
dfs(v);
}
r[u]=idx;
}
vector<int>ve;
void solve() {
cin>>n>>m;
ve=vector<int>(n+1);
for(int i=1;i<=n;++i){
cin>>ve[i];
}
g=vector<vector<int>>(n+1);
to=l=r=vector<int>(n+5);
for(int i=2;i<=n;++i){
int x;
cin>>x;
g[x].push_back(i);
}
dfs(1);
for(int i=1;i<=n;++i)add(to[i],ve[i]);
while(m--){
int op,a,x;
cin>>op;
if(op==1){
cin>>a>>x;
add(to[a],x);
}else{
cin>>a;
cout<<get(l[a],r[a])<<'\n';
}
}
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
// cin>>t;
// init();
while(t--){
solve();
}
return 0;
}