2022年天梯赛上海理工大学校内选拔赛【部分题 题解】

题目地址:https://ac.nowcoder.com/acm/contest/30532
题目难度偏简单,做出了7道快8道,认真做可能估计8-9道左右。

目录

  • A+B Problem【签到】
  • Komorebi的数学课【快速幂板子】
  • 次佛锅【哈希表 字符串处理】
  • Setsuna的K数列【k进制 思维】
  • Wiki下象棋【BFS】
  • 黄金律法【贪心】
  • 天气预报【双指针】
  • 叠硬币【DP】
  • A+B Problem again【trie树】
  • 史东薇尔城【最短路】
  • 剪绳子【思维】
  • 数硬币【线段树 区间加 区间查询最大公约数 区间求和】

A+B Problem【签到】

2022年天梯赛上海理工大学校内选拔赛【部分题 题解】_第1张图片

#include
using namespace std;
const int N=1e5+10;
int a[N],b[N],n;
int main(void) 
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i],b[i]=a[i];
    sort(a,a+n);
    for(int i=0;i<n;i++) 
    {
        if(b[i]==a[n-1]) cout<<b[i]+a[n-2]<<" "; //是最大值,则加倒数第二数
        else cout<<b[i]+a[n-1]<<" ";
    }
	return 0;
}

Komorebi的数学课【快速幂板子】

2022年天梯赛上海理工大学校内选拔赛【部分题 题解】_第2张图片

#include
using namespace std;
typedef long long int LL;
LL n;
LL quick(LL a,LL b,LL p)
{
    LL sum=1;
    while(b)
    {
        if(b&1) sum=sum*a%p;
        b>>=1;
        a=a*a%p;
    }
    return sum%p;
}
int main(void) 
{
    cin>>n;
    cout<<quick(n,n,n+2)<<endl;
	return 0;
}

次佛锅【哈希表 字符串处理】

2022年天梯赛上海理工大学校内选拔赛【部分题 题解】_第3张图片
关键点在于处理,第一行的数据。

#include
using namespace std;
string a,b;
map<string,int>mp;
vector<string>ve;
int main(void) 
{
    getline(cin,a);
    stringstream l(a);
    int cnt=0;
    while(l>>b)
    {
        cnt++;
        ve.push_back(b);
        if(cnt==2)//说明一个名字  一个数字了
        {
            mp[ve[0]]+=stoi(ve[1]);
            ve.clear();
            cnt=0;
        }
    }
    int n; cin>>n;
    while(n--)
    {
        cin>>a;
        cout<<mp[a]<<endl;
    }
	return 0;
}

Setsuna的K数列【k进制 思维】

2022年天梯赛上海理工大学校内选拔赛【部分题 题解】_第4张图片
就是k进制,之前见过类似的题目。关键在于读懂题。

#include
using namespace std;
typedef long long int LL;
const int mod=1e9+7;
LL n,f[100],k;
vector<LL>ve;
int main(void) 
{   
    cin>>n>>k;
    for(LL i=0,j=1;i<=31;i++,j=j*k%mod) f[i]=j%mod;
    LL sum=0;
    for(int i=31;i>=0;i--)
        if(n>>i&1) sum=(sum+f[i])%mod;
    cout<<sum;
	return 0;
}

Wiki下象棋【BFS】

2022年天梯赛上海理工大学校内选拔赛【部分题 题解】_第5张图片

#include
using namespace std;
typedef pair<int,int> PII;
typedef long long int LL;
const int N=510;
int t,n,m,k,a,b,c,d;
int s[N][N],st[N][N],dist[N][N];
int bfs(int x,int y,int w)
{
    memset(st,0,sizeof st);
    memset(dist,0x3f,sizeof dist);
    queue<PII>q; q.push({a,b}); st[a][b]=1; dist[a][b]=0;
    int dx[8]={};
    while(q.size())
    {
        auto temp=q.front(); q.pop();
        int x=temp.first,y=temp.second;
        if(x==c&&y==d) return dist[x][y];
        if(w==1)
        {
            int dx[8]={-2,-2,1,1,-1,-1,2,2};
            int dy[8]={-1,1,-2,2,-2,2,-1,1};
            for(int i=0;i<8;i++)
            {
                int tempx=x+dx[i],tempy=y+dy[i];
                if(tempx<1||tempx>n||tempy<1||tempy>m) continue;
                if(st[tempx][tempy]) continue;
                if(s[tempx][tempy]) continue;
                st[tempx][tempy]=1;
                dist[tempx][tempy]=dist[x][y]+1;
                q.push({tempx,tempy});
            }
        }else
        {
            int dx[8]={-2,-2,1,1,-1,-1,2,2};
            int dy[8]={-1,1,-2,2,-2,2,-1,1};
            int dx1[8]={-1,-1,0,0,0,0,1,1};//马脚
            int dy1[8]={0,0,-1,1,-1,1,0,0};//马脚
            for(int i=0;i<8;i++)
            {
                int tempx=x+dx[i],tempy=y+dy[i];
                if(tempx<1||tempx>n||tempy<1||tempy>m) continue;
                if(st[tempx][tempy]) continue;
                if(s[tempx][tempy]) continue;
                if(s[x+dx1[i]][y+dy1[i]]) continue;//憋马脚了
                st[tempx][tempy]=1;
                dist[tempx][tempy]=dist[x][y]+1;
                q.push({tempx,tempy});
            }
        }
    }
    return -1;
}
int main(void) 
{
    cin>>t;
    while(t--)
    {
        scanf("%d%d%d%d%d%d%d",&n,&m,&k,&a,&b,&c,&d);
        memset(s,0,sizeof s);
        while(k--)
        {
            int x,y; scanf("%d%d",&x,&y);
            s[x][y]++;
        }
        int ans1=bfs(a,b,1);
        int ans2=bfs(a,b,2);
        printf("%d %d\n",ans1,ans2);
    }
	return 0;
}

黄金律法【贪心】

2022年天梯赛上海理工大学校内选拔赛【部分题 题解】_第6张图片

#include
using namespace std;
typedef long long int LL;
const int N=1e6+10;
int t,n,a[N],b[N];
bool cmp(int a,int b){return a>b;}
int main(void) 
{
    cin>>t;
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=n;i++) scanf("%d",&b[i]);
        LL sum=0;
        sort(a+1,a+n+1);
        sort(b+1,b+n+1,cmp);
        for(int i=1;i<=n;i++) sum+=1ll*a[i]*b[i];
        cout<<sum<<endl;
    }
	return 0;
}

天气预报【双指针】

2022年天梯赛上海理工大学校内选拔赛【部分题 题解】_第7张图片
很容易的分析出,它是有单调性的。即当右边界满足的时候,后面的也一定满足。
故可以双指针来维护,需要注意的是 a==0 b==0 这种情况,还需额外加1。因为题目说了可以啥都不选。

#include
using namespace std;
const int N=1e6+10;
typedef unsigned long long int LL;
LL n,a,b,s[N];
string c;
bool check(int i,int j)
{
    int l=s[j]-s[i-1];
    int r=(j-i+1)-l;
    if(l>=b&&r>=a) return true;
    return false;
}
int main(void)
{
	cin>>n>>a>>b>>c;
	c="*"+c;
	for(int i=1;i<=n;i++) s[i]=s[i-1]+c[i]-'0';
	long long int ans=0;
	for(int i=1,j=1;i<=n;i++)
	{
	    while(j<=n&&!check(i,j)) j++;
	    while(j<=n&&j<i) j++;
	    if(j<=n&&check(i,j)) ans+=(n-j+1);
	}
	if(!a&&!b) ans++;
	cout<<ans;
	return 0;
}

叠硬币【DP】

2022年天梯赛上海理工大学校内选拔赛【部分题 题解】_第8张图片
2022年天梯赛上海理工大学校内选拔赛【部分题 题解】_第9张图片
这道还是挺有意思的,难度就在于输出,以及字典序最小输出。
我们可以从大到小排序。这样的话它会一直的覆盖,此时最后的就是做小的字典序。
存前驱结点可以用一个数组来存。

#include
using namespace std;
const int N=3010;
int f[N],a[N],pre[N],n,m; //pre[i] 表示放到i高时的 最后一个硬币的高度
bool cmp(int a,int b){return a>b;}
int main(void)
{
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+n+1,cmp);
    for(int i=0;i<N;i++) f[i]=1e9;
    f[0]=0,pre[0]=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=m;j>=a[i];j--)
        {
            if(f[j]>f[j-a[i]]+1 || (f[j] == f[j-a[i]]+1 && pre[j] > a[i])){
                f[j] = f[j-a[i]]+1;
                pre[j] = a[i];
            }
        }
    }
    if(f[m]>=1e9)
    {
        cout<<-1;
        return 0;
    }
    cout<<f[m]<<endl;
    vector<int>ve;
    for(int i=m;i>0;i-=pre[i]) ve.push_back(pre[i]);
    sort(ve.begin(),ve.end());
    for(int i=0;i<ve.size();i++) cout<<ve[i]<<" ";
    return 0;
}

A+B Problem again【trie树】

2022年天梯赛上海理工大学校内选拔赛【部分题 题解】_第10张图片
可以很快的想到trie树,但是处理的话相对于传统的异或trie多了一步的扩展。

#include
using namespace std;
const int N=1e5*3+10;
int son[N*6][10],cnt[N*6],idx;
int n,a[N],numbre[N];
void add(int x,int c)
{
    for(int i=0;i<=5;i++)
        numbre[i]=x%10,x/=10;
    int p=0;
    for(int i=5;i>=0;i--)
    {
        int u=numbre[i];
        if(!son[p][u]) son[p][u]=++idx;
        p=son[p][u];
        cnt[p]+=c;
    }
}
int query(int x)
{
    int sum=0;
     for(int i=0;i<=5;i++)
        numbre[i]=x%10,x/=10;
    int p=0;
    for(int i=5;i>=0;i--)
    {
        int maxv=0,index=0;
        for(int j=0;j<=9;j++) //枚举找到最大的满足条件的
        {
            if(son[p][j]&&cnt[son[p][j]])
            {
                int temp=(numbre[i]+j)%10;
                if(temp>=maxv) maxv=temp,index=j;
            }
        }
        sum=sum*10+maxv; 
        p=son[p][index];
    }
    return sum;
}
int main(void)
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i],add(a[i],1);
    for(int i=1;i<=n;i++)
    {
        add(a[i],-1);
        cout<<query(a[i])<<" ";
        add(a[i],1);
    }
    return 0;
}

史东薇尔城【最短路】

2022年天梯赛上海理工大学校内选拔赛【部分题 题解】_第11张图片

#include
using namespace std;
const int N=1e6*2+10;
typedef long long int LL;
typedef pair<LL,LL> PII;
int h[N],e[N],w[N],ne[N],idx;
LL dist[N];
int st[N],n,m;
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void  spfa()
{
    for(int i=1;i<=n;i++) dist[i]=1e18;
    dist[1]=0;
    priority_queue<PII,vector<PII>,greater<PII>>q; q.push({0,1});
    while(q.size()) 
    {
        auto temp=q.top(); q.pop();
        int u=temp.second;
        if(st[u]) continue;
        st[u]=1;
        for(int i=h[u];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dist[j]>dist[u]+w[i])
            {
                dist[j]=dist[u]+w[i];
                q.push({dist[j],j});
            }
        }
    }
}
int main(void)
{
    memset(h,-1,sizeof h);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int a,b,c; scanf("%d%d%d",&a,&b,&c);
        add(a,b,c),add(b,a,c);
    }
    int t; cin>>t;
    spfa();
    while(t--)
    {
        int a,b; scanf("%d%d",&a,&b);
        printf("%lld\n",dist[a]+dist[b]);
    }
    return 0;
}

剪绳子【思维】

2022年天梯赛上海理工大学校内选拔赛【部分题 题解】_第12张图片

#include
using namespace std;
vector<double>ve;
int n;
int main(void)
{
    cin>>n;
    ve.push_back(0),ve.push_back(10);
    for(int i=0;i<n;i++)
    {
        string op; cin>>op;
        if(op=="C")
        {
            double x; cin>>x;
            ve.push_back(x);
            sort(ve.begin(),ve.end());
        }else
        {
            double x; cin>>x;
            if(x==10) printf("%.5lf\n",10-ve[ve.size()-2]);//最后一个位置
            else
            {
                int index=upper_bound(ve.begin(),ve.end(),x)-ve.begin();
                printf("%.5lf\n",ve[index]-ve[index-1]);
            }
        }
    }
    return 0;
}

数硬币【线段树 区间加 区间查询最大公约数 区间求和】

2022年天梯赛上海理工大学校内选拔赛【部分题 题解】_第13张图片
线段树维护最大公约数,树状数组来进行区间查询。

#include 
#include 
#include 
using namespace std;
typedef long long LL;
const int N = 500010;
struct Node
{
    int l, r;
    LL sum, d;
}tr[N * 4];
LL tr1[N],tr2[N];
LL w[N];
int n,m;
LL gcd(LL a, LL b) {return b ? gcd(b, a % b) : a;}
void pushup(Node &u,Node &l,Node &r)
{
    u.sum=l.sum+r.sum;
    u.d=gcd(l.d,r.d);
}
void pushup(int u)
{
    pushup(tr[u],tr[u<<1],tr[u<<1|1]);
}
void build(int u,int l,int r)
{
    if(l==r)
    {
        LL d=w[r]-w[r-1];
        tr[u]={l,r,d,d};
    }
    else
    {
        tr[u]={l,r};
       int mid=l+r>>1;
       build(u<<1,l,mid),build(u<<1|1,mid+1,r);
       pushup(u);
    }
    
}

Node query(int u,int l,int r)
{
    if(tr[u].l>=l&&tr[u].r<=r) return tr[u];
    else
    {
        int mid=tr[u].l+tr[u].r>>1;
        if(r<=mid) return query(u<<1,l,r);
        else if(l>mid) return query(u<<1|1,l,r);
        else
        {
            auto left=query(u<<1,l,r);
            auto right=query(u<<1|1,l,r);
            Node res;
            pushup(res,left,right);
            return res;
        }
    }
}


void modify(int u,int x, LL v)
{
    if(tr[u].l==x&&tr[u].r==x) 
    {
        LL b=tr[u].sum+v;
        tr[u]={x,x,b,b};
    }
    else
    {
        int mid=tr[u].l+tr[u].r>>1;
        if(x<=mid) modify(u<<1,x,v);
        else modify(u<<1|1,x,v);
        pushup(u);
    }
}

int lowbit(int x)
{
    return x&-x;
}

void add(LL tr[],int x,LL c)
{
    for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=c;
}

LL sum(LL tr[],int x)
{
    LL res=0;
    for(int i=x;i;i-=lowbit(i)) res+=tr[i];
    return res;
}

LL get(int x)
{
    return sum(tr1,x)*(x+1)-sum(tr2,x);
}

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>w[i];
    
    build(1,1,n);
    for(int i=1;i<=n;i++)
    {
        int d=w[i]-w[i-1];
        add(tr1,i,d),add(tr2,i,(LL)i*d);
    }
    
    
    while (m -- )
    {
        int op;
        int l,r;
        cin>>op>>l>>r;
        if(l>r) swap(l,r);
        if(op==2)
        {
            auto left=query(1,1,l);
            Node right={0,0,0,0};
            if(l+1<=r) right=query(1,l+1,r);
            printf("%lld\n",abs(gcd(left.sum,right.d)));
        }
        else if(op==0)
        {
            LL d;
            cin>>d;
            add(tr1,l,d),add(tr1,r+1,-d);
            add(tr2,l,l*d),add(tr2,r+1,(r+1)*-d);
            modify(1,l,d);
            if(r+1<=n) modify(1,r+1,-d);
        }
        else
        {
            printf("%lld\n",get(r)-get(l-1));
        }
    }
    return 0;
}

你可能感兴趣的:(#,编程比赛总结,c++,算法)