西南民族大学 2024 天梯选拔赛(一)
A 私人笑声
查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define double long double
const int N=1e5+5;
void solve(){
string s;
getline(cin,s);
for(int i=0;i<s.size();++i){
cout<<s[i];
if(s[i]=='.')cout<<"xixixixi.";
}
}
int32_t main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t=1;
// cin>>t;
while (t--){
solve();
}
}
B 孵化小鸡
思路:暴力
横轴范围不大,记录横轴上需要的温度,由于加热器最多10个,用0~2m-1的二进制数表示加热器的选取情况,对横轴进行加热处理后判断是否都能满足,统计最少花费
查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define double long double
#define PII pair<int,int>
const int N=1e6+5,INF=0x3f3f3f3f3f;
struct E{
int l,r,k,p;
};
void solve(){
int n,m;
cin>>n>>m;
vector<int>ve(101);
for(int i=0;i<n;++i){
int a,b,mm;
cin>>a>>b>>mm;
for(int j=a;j<=b;++j)ve[j]=max(ve[j],mm);
}
vector<E>g(m);
for(int i=0;i<m;++i)cin>>g[i].l>>g[i].r>>g[i].k>>g[i].p;
int cost=1e9;
for(int i=0;i<1<<m;++i){
vector<int>f=ve;
int now=0;
for(int j=0;j<m;++j){
if((i>>j)&1){
for(int k=g[j].l;k<=g[j].r;++k){
f[k]-=g[j].k;
}
now+=g[j].p;
}
}
bool ok=true;
for(int j=1;j<=100;++j){
if(f[j]>0){
ok=false;
break;
}
}
if(ok)cost=min(cost,now);
}
cout<<cost;
}
int32_t main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t=1;
// cin>>t;
while (t--){
solve();
}
}
C 可怕的冻雨
思路:贪心模拟
首先能够站在一个冰地的前提条件是当前鞋的防滑值不小于该冰地的滑度。对于当前鞋子的防滑值,找出所有能够站立的冰地。现在要考虑可以跳跃的情况,需要从0跳到n。已知能够站立的冰地后,通过判断相邻的能够站立的冰地之间的距离是否不大于该鞋子能够跳跃的最大距离s可以判断该鞋子是否能从0跳到n。
由于所有能够站立的冰地只由鞋子的防滑值决定,且能从0跳到n由鞋子的s决定,那么将鞋子由防滑值进行升序排序,将冰地由滑度也进行升序排序。先处理防滑值最小的鞋子。这里用set存能够站立的冰地位置(可以保证位置是递增的),用multiset存相邻能够站立的冰地的距离。判断nultiset中最大值与当前鞋子的s的大小即可判断能否从0跳到n。对于下一个鞋子,由于鞋子的防滑值是递增的,这里需要在上一个鞋子能够站立的冰地的基础上再添加该鞋子能够站立的冰地,再更新set和multiset,(由于添加冰地会更改相邻冰地的距离)在添加过程中,需要更新multiset中的值,即找到添加的冰地的前后冰地位置按情况对距离进行删添。更新完后同理进行判断能否从0跳到n。
查看代码
#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};
struct E{
int f,s,id;
bool operator<(const E&e)const{
return f<e.f;
}
};
set<int>se;
multiset<int>len;
void eral(int l){
len.erase(len.find(l));
}
void solve() {
int n,m;
cin>>n>>m;
vector<PII>ve(n);
for(int i=0;i<n;++i)cin>>ve[i].first,ve[i].second=i;
vector<E>g(m);
for(int i=0;i<m;++i)cin>>g[i].f>>g[i].s,g[i].id=i;
vector<int>ans(m);
sort(ve.begin(),ve.end());
sort(g.begin(),g.end());
int idx=0;
while(idx<n&&ve[idx].first<=g[0].f){
se.insert(ve[idx++].second);
}
int pre=0;
for(auto u:se){
len.insert(u-pre);
pre=u;
}
se.insert(0);
if(*--len.end()<=g[0].s)ans[g[0].id]=1;
for(int i=1;i<m;++i){
while(idx<n&&ve[idx].first<=g[i].f){
auto p=se.upper_bound(ve[idx].second);
if(p==se.end()){
p--;
se.insert(ve[idx].second);
len.insert(ve[idx].second-*p);
}else{
auto l=prev(p);
eral(*p-*l);
se.insert(ve[idx].second);
len.insert(ve[idx].second-*l),len.insert(*p-ve[idx].second);
}
idx++;
}
if(*--len.end()<=g[i].s)ans[g[i].id]=1;
}
for(int i=0;i<m;++i){
cout<<ans[i]<<'\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;
}
D 划分田地(easy)
思路:暴力
由于n不大,用0~2n-1的二进制数表示每个点的选取情况,求出包含这些点的最小矩形(用4条边表示),用set存下有多少种即可
查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define double long double
#define PII pair<int,int>
const int N=1e5+5;
struct E{
int x,y;
};
void solve(){
int n;
cin>>n;
vector<PII>ve(n);
for(int i=0;i<n;++i)cin>>ve[i].first>>ve[i].second;
set<vector<int>>se;
for(int i=1;i<1<<n;++i){
vector<int>a(4);
int x1=55,x2=-1,y1=55,y2=-1;
for(int j=0;j<n;++j){
if((i>>j)&1){
x1=min(x1,ve[j].second);
x2=max(x2,ve[j].second);
y1=min(y1,ve[j].first);
y2=max(y2,ve[j].first);
}
}
// cout<<x1<<' '<<x2<<' '<<y1<<' '<<y2<<'\n';
a[0]=x1,a[1]=x2,a[2]=y1,a[3]=y2;
se.insert(a);
}
cout<<se.size()+1;
}
int32_t main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t=1;
// cin>>t;
while (t--){
solve();
}
}
E 划分田地(hard)
思路:可以看到点的范围很大,但是点的数量不多,就可以进行离散化处理。可以先枚举两个点,对于两点形成的最小矩形,定一对平行边,另一对平行边可以任意移动来构成新的矩形,只需要分别知道两边的点数,两边点数的乘积便是在该已定平行边的情况下的矩形个数
查看代码
#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 ve(2,vector<int>(n));
for(int i=0;i<n;++i){
cin>>ve[0][i]>>ve[1][i];
}
map<int,int>xid,yid;
int idx=1;
auto g=ve;
sort(ve[0].begin(),ve[0].end());
for(int i=0;i<n;++i)xid[ve[0][i]]=idx++;
idx=1;
sort(ve[1].begin(),ve[1].end());
for(int i=0;i<n;++i)yid[ve[1][i]]=idx++;
// cout<<xn<<' '<<yn<<'\n';
vector<vector<int>>f(n+5,vector<int>(n+5));
vector<PII>q;
for(int i=0;i<n;++i){
g[0][i]=xid[g[0][i]],g[1][i]=yid[g[1][i]];
f[g[0][i]][g[1][i]]=1;
q.push_back({g[0][i],g[1][i]});
}
auto cmp=[](PII a,PII b){
return a.first<b.first;
};
sort(q.begin(),q.end(),cmp);
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
f[i][j]+=f[i-1][j]+f[i][j-1]-f[i-1][j-1];
}
}
auto get=[f](int x1,int y1,int x2,int y2){
return f[x2][y2]-f[x1-1][y2]-f[x2][y1-1]+f[x1-1][y1-1];
};
int ans=0;
for(int i=0;i<n;++i){
for(int j=i+1;j<n;++j){
int ix=q[i].first,iy=q[i].second,jx=q[j].first,jy=q[j].second;
int x1=min(ix,jx);
int x2=max(ix,jx);
int y1=min(iy,jy);
int y2=max(iy,jy);
int a=get(x1,1,x2,y1-1);
int b=get(x1,y2+1,x2,n);
ans+=(a+1)*(b+1);
}
}
cout<<ans+1+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;
}
F 加一余二
思路:模拟
由于可能会有多个长度相同的相同连续串,修改一个字符时无法判断其他串的情况,那么就要记录所有的连续串。记录每个连续串的起始点(保证有序),以及用multiset记录所有连续串的长度。
每次修改,首先找到修改位置x所在的连续串,分几种情况:
1.所在串长度为1:那么就是合并左右两边的连续串(注意左串或右串不存在的情况)
2.所在串长度不为1,x是串起点,那么就是将x与左边的连续串合并,所在串的剩余部分为一个串(注意左串或右串不存在的情况)
3.所在串长度不为1,x是串终点,同理2(注意左串或右串不存在的情况)
4.所在串长度不为1,x不为串起点或终点,那就是将串分为三个部分:x左边部分、x单独、x右边部分
查看代码
#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};
set<PII>ve;
multiset<int>cnt;
int len(PII a){
return a.second-a.first+1;
}
PII find(int x){
auto p=ve.upper_bound(make_pair(x,N));
p--;
// cout<<p->first<< ' '<<p->second<<'\n';
return *p;
}
void era(PII p){
ve.erase(ve.find(p)),cnt.erase(cnt.find(len(p)));
}
void add(PII p){
ve.insert(p),cnt.insert(len(p));
}
void solve() {
string s;
cin>>s;
int n,m;
n=s.size();
cin>>m;
s.insert(s.begin(),' ');
for(int i=1;i<=n;++i) {
int j = i;
while (j + 1 <= n && s[j + 1] == s[i])j++;
ve.insert(make_pair(i,j));
cnt.insert(len(make_pair(i,j)));
i = j;
}
// cout<<ve.size()<<'\n';
// for(auto v:ve){cout<<v.first<<' '<<v.second<<'\n';}
// auto c=find(3);
// cout<<c.first<<' '<<c.second;
while(m--){
int x;
cin>>x;
auto p=find(x);
// cout<<x<<":"<<p.first<<' '<<p.second<<' ';
era(p);
if(p.first==p.second){//11011
if(x!=1){
auto l=find(x-1);
era(l);
p.first=l.first;
}
if(x!=n){
auto r=find(x+1);
era(r);
p.second=r.second;
}
add(p);
}else if(p.first==x){//0111
if(x!=1){
auto l=find(x-1);
era(l);
l.second=x;
add(l);
}else{
add({x,x});
}
p.first=x+1;
add(p);
}else if(p.second==x){
if(x!=n){
auto r=find(x+1);
// cout<<'|'<<r.first<<' '<<r.second<<'|';
era(r);
r.first=x;
add(r);
}else{
add({x,x});
}
p.second=x-1;
add(p);
}else{
PII l={p.first,x-1},r={x+1,p.second};
add(l),add(r);
add({x,x});
}
cout<<*--cnt.end()<<' ';
}
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
// cin>>t;
// init();
while(t--){
solve();
}
return 0;
}
G 相加余三(easy)
思路:暴力枚举
查看代码
#include<bits/stdc++.h>
using namespace std;
//#define int long long
#define double long double
#define PII pair<int,int>
const int N=1e5+5;
const int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
void solve(){
int n;
cin>>n;
vector<int>a(n+1);
for(int i=1;i<=n;++i){
cin>>a[i];
}
int ans=0;
int res=0;
for(int i=1;i+1<=n;i+=2){
res+=(a[i]+a[i+1])%3;
}
ans=max(ans,res);
res=0;
for(int i=n;i-1>=1;i-=2){
res+=(a[i]+a[i-1])%3;
}
ans=max(ans,res);
int l=1,r=n;
res=0;
while(l<r){
res+=(a[l]+a[r])%3;
l++,r--;
}
ans=max(ans,res);
cout<<ans;
}
int32_t main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t=1;
// cin>>t;
while (t--){
solve();
}
}
H 相加余三(hard)
思路:区间dp
当前区间状态可以由区间长度更小的状态转移而来,有三种转移方法,取最大的一种即可
查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define double long double
#define PII pair<int,int>
const int N=1e6+5,INF=0x3f3f3f3f3f;
void solve(){
int n;
cin>>n;
// cout<<n<<'\n';
vector<int>a(n+1);
for(int i=1;i<=n;++i){
cin>>a[i];
// cout<<i<<'\n';
}
vector<vector<int>>f(n+1,vector<int>(n+1));
for(int i=2;i<=n;++i){
for(int j=1;j+i-1<=n;++j){
int l=j,r=j+i-1;
if(i==2)f[l][r]=(a[l]+a[r])%3;
else{
f[l][r]=max(f[l][r],f[l+2][r]+(a[l]+a[l+1])%3);
f[l][r]=max(f[l][r],f[l][r-2]+(a[r-1]+a[r])%3);
f[l][r]=max(f[l][r],f[l+1][r-1]+(a[l]+a[r])%3);
}
// cout<<f[l][r]<<' ';
}
}
cout<<f[1][n];
}
int32_t main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t=1;
// cin>>t;
while (t--){
solve();
}
}
I 找除数
思路:实际上就是找n的所有约数(再加上0),一个数的形式可以为n=p1k1p2k2p3k3...,(p为质数),那么就是找n的所有质因子p,以及个数k,对于该因子有k+1种选法:不选、p、p2、p3...、pk。将所有质因子的选法乘起来就是答案。直接枚举的话会T,由于质因子(除本身外)最大为1e4,可以预处理出所有1e4内的质数,在枚举质数即可
查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define double long double
#define PII pair<int,int>
const int N=1e5+5,INF=0x3f3f3f3f3f;
int primes[N],cnt;
bool st[N];
void init(){
for(int i=2;i<=1e5;++i){
if(!st[i])primes[cnt++]=i;
for(int j=0;primes[j]*i<=1e5;++j){
st[primes[j]*i]=true;
if(i%primes[j]==0)break;
}
}
}
void solve(){
int n;
cin>>n;
int ans=1;
for(int i=0;primes[i]*primes[i]<=n&&i<cnt;++i){
if(n%primes[i]==0){
int c=0;
while(n%primes[i]==0){
n/=primes[i];
c++;
}
ans*=(c+1);
}
}
if(n>1)ans*=2;
cout<<ans<<'\n';
}
int32_t main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t=1;
cin>>t;
init();
while (t--){
solve();
}
}
J 最后都是0
思路:暴力
查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define double long double
#define PII pair<int,int>
const int N=1e5+5;
void solve(){
int n;
cin>>n;
int ans=0;
auto P=[](int u){
int ma=0;
while(u){
ma=max(ma,u%10);
u/=10;
}
return ma;
};
while(n>0){
int c=P(n);
n-=c;
ans++;
}
cout<<ans;
}
int32_t main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t=1;
// cin>>t;
while (t--){
solve();
}
}
K 第五人格,启动!
思路:暴力
每走一步的用时都增加,所以要尽可能少走,对于已定的抓人顺序的路径一定是最短路径,对于有墙的路径求终点到所有点的最短路即可。枚举抓人顺序求最短路径
查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define double long double
#define PII pair<int,int>
const int N=1e5+5;
const int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
struct E{
int x,y;
};
void solve(){
int n,m;
cin>>n>>m;
vector<vector<int>>d(n+1,vector<int>(m+1,1e9));
vector<string>ve(n+1);
for(int i=1;i<=n;++i){
cin>>ve[i];
ve[i].insert(ve[i].begin(),' ');
}
int sx,sy,ex,ey;
vector<E>f(4);
cin>>sx>>sy;
for(int i=1;i<=3;++i)cin>>f[i].x>>f[i].y;
cin>>ex>>ey;
vector<int>t(4);
cin>>t[1]>>t[2]>>t[3];
d[ex][ey]=0;
queue<E>q;
q.push({ex,ey});
while(q.size()){
auto u=q.front();
q.pop();
for(int i=0;i<4;++i){
int x=u.x+dx[i],y=u.y+dy[i];
if(x<1||x>n||y<1||y>m||ve[x][y]=='#')continue;
if(d[x][y]>d[u.x][u.y]+1){
d[x][y]=d[u.x][u.y]+1;
q.push({x,y});
}
}
}
auto P=[&](int a,int b,int c){
int res=0;
res+=abs(sx-f[a].x)+abs(sy-f[a].y);
int h=abs(f[a].x-f[b].x)+abs(f[a].y-f[b].y);
res+=h*(1+t[a]);
h=abs(f[b].x-f[c].x)+abs(f[b].y-f[c].y);
res+=h*(1+t[a]+t[b]);
res+=d[f[c].x][f[c].y]*(1+t[a]+t[b]+t[c]);
return res;
};
int ans=2e9;
ans=min(ans,P(1,2,3));
ans=min(ans,P(1,3,2));
ans=min(ans,P(2,1,3));
ans=min(ans,P(2,3,1));
ans=min(ans,P(3,1,2));
ans=min(ans,P(3,2,1));
cout<<ans;
}
int32_t main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t=1;
// cin>>t;
while (t--){
solve();
}
}
L 加纳~
查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define double long double
const int N=1e5+5;
void solve(){
int n,m;
cin>>n>>m;
int k;
cin>>k;
int ans=k/n;
if(k%n>=m)ans++;
cout<<ans;
}
int32_t main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t=1;
// cin>>t;
while (t--){
solve();
}
}