题解 | #小竹与妈妈#

小竹与妈妈

https://ac.nowcoder.com/acm/contest/45670/A

A.
显然小竹的年龄为  直接输出即可。
#include<bits/stdc++.h>
using namespace std;
int a,b,x;
int main()
{
    cin>>a>>b>>x;
    cout<<(x-b)/a<<'\n';
    return 0;    
}
B.
记录每个房间有多少个出口连接记为cnt,每次询问输出n-cnt_x即可。
#include<bits/stdc++.h>
using namespace std;
int cnt[100005];
int n,m,q;

int main()
{
    cin>>n>>m>>q;
    assert(1<=n&&n<=1e5);
    assert(1<=m&&m<=1e5);
    assert(1<=q&&m<=1e5);
    for(int i = 1;i<=n;++i)
    {
        int x;
        cin>>x;
        assert(1<=x&&x<=m);
        cnt[x]++;    
    }
    while(q--)
    {
        int x;
        cin>>x;
        assert(1<=x&&x<=m);
        cout<<(n-cnt[x])<<'\n';    
    }
    
    return 0;
} 

C.
用一个  的 dp 即可解决该问题。
设 dp_i 为选择前 i 个数绳子的最大长度。
很容易能列出  。
由于允许  通过,直接模拟该过程即。最后的答案为

#include<bits/stdc++.h>
using namespace std;
int n,k;
int a[2005];
int dp[2005];
int ans;
 
int main()
{
    cin>>n>>k;
    assert(1<=n&&n<=2000);
    assert(1<=k&&k<=n);
    for(int i = 1;i<=n;++i)
    {
        cin>>a[i];
        assert(a[i]<=2000&&a[i]>=1);
    }
    for(int i = 1;i<=n;++i)
        for(int j = 0;j<=max(0,i-k-1);++j)
        {
            dp[i] = max(dp[j]+a[i],dp[i]);
            ans = max(ans,dp[i]);
        }
    cout<<ans<<'\n';
      
    return 0;
 }

D.
从起点开始 bfs 求出起点到每个位置的最短路,从终点开始同样跑一遍 bfs 求出终点到每个位置的最短路.对于每一个拥有刺激度高于 x 游戏的店铺 p ,要经过该店铺的答案即为起点到 p 的最短路,加上终点到 p 的最短路
时间复杂度 O(nm);
#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,m,x;
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int sx,sy,ex,ey;
    assert(cin>>n>>m>>x);
    assert(cin>>sx>>sy>>ex>>ey);
    vector<vector<int>> s(n,vector<int>(m));
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            assert(cin>>s[i][j]);
    sx--,sy--,ex--,ey--;
    s[sx][sy]=0,s[ex][ey]=0;
    vector<vector<int>> dista(n,vector<int>(m,1e9)),distb=dista;
    function<void(vector<vector<int>>&,int,int)> bfs=[&](vector<vector<int>> &dist,int x,int y)->void{
        array<int,4> dx ={-1,1,0,0},dy ={0,0,-1,1};
        dist[x][y]=0;
        using PII = pair<int,int>;
        queue<PII> qe;
        qe.push({x,y});
        while(qe.size()){
            PII var = qe.front();
            qe.pop();
            for(int i=0;i<4;i++){
                int x= var.first+dx[i],y=var.second+dy[i];
                if(x<0||y<0||x>=n||y>=m)continue;
                if(s[x][y]==-1)continue;
                if(dist[x][y] > dist[var.first][var.second]+1){
                    dist[x][y] = dist[var.first][var.second]+1;
                    qe.push({x,y});
                }
            }
        }
    };
    bfs(dista,sx,sy),bfs(distb,ex,ey);
    int ans = 1e9;
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            if(s[i][j]>x)
                ans = min(ans,dista[i][j]+distb[i][j]);
    if(ans==1e9)
        ans=-1;
    cout << ans<<"\n";
}
E.
相邻结点满足有至少两个不同的共同质因子,也就相当于,相邻两个结点的  满足不为任何质数的幂次,且不为1

我们可以把所有质数的幂次使用一个标记数组 flag 标记起来,然后进行树形dp

设 dp_i 为以 i 为根的最大优雅联通块,设 son_i 为 i 的子节点的集合,则


#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6;
int f[5*maxn+5];
int p[5*maxn+5];
int dp[maxn+5];
int a[maxn+5];
int n;
int ans;
vector<int> edge[maxn+5];
void dfs(int x,int fa)
{
    dp[x] = 1;
    for(auto v:edge[x])
    {
        if(v==fa) continue;
        dfs(v,x);
        if(!f[(__gcd(a[v],a[x]))])
            dp[x]+=dp[v]; 
    }
    ans = max(dp[x],ans);
}
int main()
{
    f[1] = 1;
    for(int i = 2;i<=5*maxn;++i)
        if(!p[i])
        {
            for(int j = i+i;j<=5*maxn;j+=i)
                p[j] = 1;
            for(long long j = i;j<=5*maxn;j*=i)
                f[j] = 1;
                 
        }
    cin>>n;
    assert(1<=n&&n<=1e6);
    for(int i = 1;i<=n;++i)
    {
        cin>>a[i];
        assert(a[i]<=5e6&&a[i]>=1);
    }
    for(int i = 1;i<n;++i)
    {
        int x,y;
        cin>>x>>y;
        assert(1<=x&&x<=n);
        assert(1<=y&&y<=n);
        edge[x].push_back(y);
        edge[y].push_back(x);
    }
    dfs(1,0);
    for(int i = 1;i<=n;++i)
        assert(dp[i]);
    cout<<ans<<'\n';

    return 0;
 } 
F.



先考虑后面那一堆式子,考虑算出每一个区间的贡献,区间内每一个数作为 x 时,造成的贡献为区间内所有大于等于该数的数的个数。那么长度为 len 的区间的贡献为 

所以直接枚举区间长度

我们发现这个式子与排列无关所以原式可以写成:

我们可以计算每一对逆序对  造成的贡献:
x 放在 y 前面有  种方案,其他位置可以随便放,所以每一对逆序对的贡献为 
共有  对不同的逆序对


答案即为 

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int t;
int n; 
vector<int> js;
const int mod = 1e9+7;
ll fac[100006];
ll ifac[100006]; 
int maxn = 1e5+4;
ll ksm(ll x, ll y)
{
    ll ret = 1;
    do {
        if ( y & 1 )
            ret = ret * x % mod;
        x = x * x % mod;
    } while ( y >>= 1 );
    return ret;
}
void init()
{
    fac[0] = 1;
    for ( int i = 1;i <= maxn;i++ ) {
        fac[i] = fac[i - 1] * i % mod;
    }
    ifac[maxn - 1] = ksm(fac[maxn - 1], mod - 2);
    for ( int i = maxn - 1;i >= 1;i-- ) {
        ifac[i - 1] = ifac[i] * i % mod;
    }
}

ll C(int x, int y)
{
    return fac[x] * ifac[y] % mod * ifac[x - y] % mod;
}

void solve()
{
    int n;
    cin>>n;
    assert(1<=n&&n<=100000);
    ll ans = (((C(n+3,4))%mod*fac[(n-2)]%mod*(1ll*n*(n-1)/2)%mod*(1ll*n*(n-1)/2)%mod))%mod;
    assert(0<=ans&&ans<=1e9+7);
    cout<<ans<<'\n'; 
}
signed main()
{
    init();
    int t;
    cin>>t;
    assert(1<=t&&t<=100000);
    while(t--)
        solve();
    return 0;
}
全部评论
F题的题面到底是个啥意思,我都没读懂。。
点赞 回复 分享
发布于 2022-11-12 14:51 河北

相关推荐

与火:这不接? 留子的钱不挣白不挣
点赞 评论 收藏
分享
13 收藏 评论
分享
牛客网
牛客企业服务