河北工業大學 ACM 集訓隊 2023 年夏季選拔 題解 12/12

https://ac.nowcoder.com/acm/contest/59007

A

假設數字n有len位

則小len的長度,每個都有九個方案。

長度和len一樣的,至少有n[0]-1種方案

n[0]n[0]n[0]...的這個方案暴力地跑一遍看看是不是小於等於n即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
    int x;scanf("%d",&x);return x;
}
char s[1000];
int len,ans;
int main()
{
    // freopen("1.in","r",stdin);
    scanf("%s",s+1);
    len=strlen(s+1);
    ans=len*9-9;
    ans++;
    for(int i=2;i<=len;i++)
        if(s[i]<s[1])
        {
            ans--;
            break;
        }
    ans+=s[1]-'1';
    cout<<ans;
}
A

B

 賽場上找規律找出來的,發現是n*n*k的因子數量-1。

考慮把n和k質因子分解,答案是∏(因子數量+1)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll read()
{
    ll x;scanf("%lld",&x);return x;
}
ll n,k,ans;
map<int,int>o;
void work()
{
    n=read();k=read();ans=1;o.clear();
    for(int i=2;i*i<=n;i++)
        while(n%i==0)
        {
            o[i]+=2;
            n=n/i;
        }
    if(n!=1)
        o[n]+=2;
    for(int i=2;i*i<=k;i++)
        while(k%i==0)
        {
            o[i]++;
            k=k/i;
        }
    if(k!=1)
        o[k]++;
    for(auto x:o)
        ans=ans*(x.second+1);
    printf("%lld\n",ans-1);
}
int main()
{
    for(ll t=read();t;t--)
        work();
}
B

賽後請數論大師@chdy做了做

 C

輸出RUSHB,連我個圈外人都知道

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
    int x;scanf("%d",&x);return x;
}
int main()
{
    // freopen("1.in","r",stdin);
    cout<<"RUSHB";
}
C

D

注意到n只有8,所以暴力跑n的排列,按題意模擬即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
    int x;scanf("%d",&x);return x;
}
double ans,sum;
int w0,w[110],x[110],y[110],noww,n,a[110];
double askdis(int u,int v)
{
    return sqrt((x[u]-x[v])*(x[u]-x[v])+(y[u]-y[v])*(y[u]-y[v]));
}
void dfs(int d)
{
    if(d==n+1)
    {
        sum=0;noww=w0;
        for(int i=1;i<=n;i++)
        {
            sum=sum+askdis(a[i],a[i-1])*noww;
            noww=noww+w[a[i]];
        }
        ans=min(ans,sum);
        return ;
    }
    for(int i=d;i<=n;i++)
    {
        swap(a[i],a[d]);
        dfs(d+1);
        swap(a[i],a[d]);
    }
}
int main()
{
    ans=1e18;
    n=read();w0=read();
    for(int i=1;i<=n;i++)
        x[i]=read();
    for(int i=1;i<=n;i++)
        y[i]=read();
    for(int i=1;i<=n;i++)
    {
        w[i]=read();
        a[i]=i;
    }
    dfs(1);
    printf("%.7lf",ans);
}
D

E

 注意到k只有50,m只有1000,所以mk地模擬一下即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
    int x;scanf("%d",&x);return x;
}
ll a[1010];
int k,m,c[60],mod=998244353;
int main()
{
    k=read();m=read();
    for(int i=1;i<=k;i++)
        c[i]=read();
    for(int i=1;i<=k;i++)
        a[i]=read();
    for(int i=k+1;i<=m;i++)
        for(int j=1;j<=k;j++)
            a[i]=(a[i]+c[j]*a[i-j])%mod;
    cout<<a[m];
}
E

F

經典前綴和。考慮把+看成1,-看成-1,區間[l,r]“正負相互抵消”等價於l-1和r的前綴和相等。

所以記錄一下每個前綴和第一次出現的位置,ans=max(每個前綴和最後一次出現的位置-第一次出現的位置)

代碼方面可以用+1000000的方式把負數前綴和轉移到正數裏,然後用數組存。或者像我一樣使用map存第一次出現的位置。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
    int x;scanf("%d",&x);return x;
}
char s[1000010];
map<int,int>f;
int sum,n,ans;
int main()
{
    f[0]=0;
    scanf("%s",s+1);
    n=strlen(s+1);
    for(int i=1;i<=n;i++)
    {
        if(s[i]=='+')
            sum++;
        else
            sum--;
        if(f.count(sum))
            ans=max(ans,i-f[sum]);
        else
            f[sum]=i;
    }
    cout<<ans;
}
F

G

問題是說給定一個對稱串,能否重新排列使得變成另一個對稱串。

那麼對稱的兩個字母必須一起行動,如果n是奇數,中間的字母不影響答案。

所以std統計一下對稱的字母的種類數,如果等於1就不能,對應着aaaaaa或者aabaa這些情況。

如果大於1就可以,此時把任意兩個不相同的字母交換一下即可。

總之,std是對的,輸出yes(話說我去cf交一下代碼不就知道對不對了)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
    int x;scanf("%d",&x);return x;
}
int main()
{
    // freopen("1.in","r",stdin);
    for(int t=read();t;t--)
        cout<<"YES\n";
}
G

H

出題人生怕不會寫,甚至把判斷凸包包含給端上來了,並且點的座標都是整數。

考慮暴力枚舉i,j,判斷如果一個在另一個裏面就連有向邊,於是會連出來一個有向無環圖。

對有向無環圖跑拓撲排序,計算深度d即可。將d排個序輸出。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
    int x;scanf("%d",&x);return x;
}
struct tnode
{
    ll x,y;
};
vector<tnode>node[110];
int n;
int in(int a,int b)
{
    ll x0=node[a][0].x;
    ll y0=node[a][0].y;
    ll x1,y1,x2,y2;
    for(int i=1;i<node[b].size();i++)
    {
        x1=node[b][i-1].x;y1=node[b][i-1].y;
        x2=node[b][i].x;y2=node[b][i].y;
        if((x1-x0)*(y2-y0)<=(x2-x0)*(y1-y0))
            return 0;
    }
    x1=node[b][node[b].size()-1].x;y1=node[b][node[b].size()-1].y;
    x2=node[b][0].x;y2=node[b][0].y;
    if((x1-x0)*(y2-y0)<=(x2-x0)*(y1-y0))
        return 0;
    return 1;
}
vector<int>e[110];
queue<int>q;
int d[110],ru[110];
priority_queue<int>ans;
int main()
{
    // freopen("1.in","r",stdin);
    n=read();
    for(int i=1;i<=n;i++)
    {
        for(int k=read();k;k--)
        {
            int x=read();
            node[i].push_back({x,read()});
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(i==j)continue;
            if(in(j,i))//
            {
                ru[j]++;
                e[i].push_back(j);
            }
        }
    }
    for(int i=1;i<=n;i++)
        if(ru[i]==0)
        {
            d[i]=1;
            q.push(i);
        }
    while(q.size())
    {
        int x=q.front();
        q.pop();
        for(auto y:e[x])
        {
            ru[y]--;
            if(ru[y]==0)
            {
                d[y]=d[x]+1;
                q.push(y);
            }
        }
    }
    for(int i=1;i<=n;i++)
        if(!e[i].size())
            ans.push(-d[i]);
    while(ans.size())
    {
        printf("%d ",-ans.top());
        ans.pop();
    }
}
H

I

計數類問題。考慮數字x在第i位的方案對答案的貢獻是pow(10,i-1)*(n-1)! *x,計算一下即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
    int x;scanf("%d",&x);return x;
}
ll n,sum,now,t,mod=1e9+7;
int main()
{
    // freopen("1.in","r",stdin);
    n=read();
    for(int i=1;i<=n;i++)
    {
        sum=sum+read();
        t=(t*10+1)%mod;
    }
    now=1;
    for(int i=1;i<n;i++)
        now=now*i%mod;
    cout<<t*sum%mod*now%mod;
}
I

J

大膽模擬,注意數組要開ll,否則1e8*32會爆掉。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll read()
{
    ll x;scanf("%lld",&x);return x;
}
ll n,m,a[210][210];
struct node
{
    ll a,b;
    char c;
}o[210][210];
char s[100];
int main()
{
//     freopen("1.in","r",stdin);
    n=read();m=read();
    if(read()&1)
    {
        scanf("%s",s);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                scanf("%lld%c%lldi",&o[i][j].a,&o[i][j].c,&o[i][j].b);
                printf("%lld%c%lldi ",o[i][j].a,o[i][j].c,o[i][j].b);
            }
            printf("\n");
        }
        printf("%ss have\n",s);
        if(s[4]=='y')
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                    o[i][j].a*=8,o[i][j].b*=8;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                printf("%lld%c%lldi ",o[i][j].a,o[i][j].c,o[i][j].b);
            printf("\n");
        }
        printf("mouths,\n");

        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                printf("%lld%c%lldi ",o[i][j].a*2,o[i][j].c,o[i][j].b*2);
            printf("\n");
        }
        printf("eyes and\n");

        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                printf("%lld%c%lldi ",o[i][j].a*4,o[i][j].c,o[i][j].b*4);
            printf("\n");
        }
        printf("legs.");
    }
    else
    {
        scanf("%s",s);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                scanf("%lld",&a[i][j]);
                printf("%lld ",a[i][j]);
            }            
            printf("\n");
        }
        printf("%ss have\n",s);

        if(s[4]=='y')
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                    a[i][j]*=8;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                printf("%lld ",a[i][j]);
            printf("\n");
        }
        printf("mouths,\n");

        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                printf("%lld ",a[i][j]*2);
            printf("\n");
        }
        printf("eyes and\n");

        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                printf("%lld ",a[i][j]*4);
            printf("\n");
        }
        printf("legs.");
    }
}
J

K

注意到ai最多有log(ai)個1,所以  以i位結尾的所有區間的與最多有log(ai)種不同的數,用set維護一下以i位結尾的區間的與。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
    int x;scanf("%d",&x);return x;
}
set<int>ans[200010];
int main()
{
    int n=read();
    for(int i=1;i<=n;i++)
    {
        int x=read();
        ans[i].insert(x);
        for(auto y:ans[i-1])
            ans[i].insert(x&y);
        printf("%d ",ans[i].size());
    }
}
K

L

大膽dp

f[i][j][kk]表示在i行第j列花費了kk活力值能獲得的最大的祝福值。

f[i][j][kk]=max(f[i-1][j][kk],f[i][j-1][kk]);

若kk>=a[s[i][j]-'0'],可以更新

f[i][j][kk]=max(f[i][j][kk],max(f[i][j-1][kk-val]+a[val],f[i-1][j][kk-val]+a[val]));

最後輸出f[n][m][k]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章