【2018 9th C++】 蓝桥杯决赛

\(1.\) 换零钞

题意

钞票一共有\(100、5、2、1\)四种,现在有\(2\)\(100\)元的钞票,去换零钱,要换出的零钱中\(2\)元的是\(1\)元的\(10\)倍,剩下的都是\(5\)元面额的

数据范围

题解

换的钱张数最少,即\(1\)元的最少,枚举\(1\)元的数目即可,然后得到\(2\)元的数目,最后判断一下剩余的金钱数能不能用\(5\)元的凑出来

Code

#include<iostream>
#include<algorithm>
using namespace std;

int main()
{
    int one=0;
    int res=0;
    for(int i=1;i<=200;i++)
    {
        if((200-i*2*10-i)%5==0)
        {
            one=i;
            res=200-(i*2*10+i);
            break;
        }    
    }
    int ans;
    ans=one+10*one;
    ans=ans+res/5;
    printf("%d\n",ans);
}

\(2.\) 激光样式

题意

\(30\)个灯,相邻的两个不能够同时亮,问一共能够有多少种不同的打开方式,全部关闭也算是一种

数据范围

\(1\leq n\leq 30\)

题解

暴力搜索所有可能的状态,全为\(0\)也算是一种

Code

#include<iostream>
using namespace std;
bool st[35];
int ans=0;
void dfs(int u,int pre){
    if(u==31){
        ans++;
        return;
    }
    if(pre==0){
        dfs(u+1,1);
    }
    dfs(u+1,0);
}
int main(){
    dfs(1,0);
    cout<<ans<<endl;
}

\(3.\) 格雷码

题意

代码填空,实现对一个数\(x\)求出其二进制下最右边的一个\(1\),并将其左边的二进制数字进行改变

数据范围

题解

\(lowbit\)操作能求出最右边的1,低位补\(0\)后的数字,将其左移一位置,即在后面加一个\(0\),求得的数字即当前最右边的\(1\)左边数字对应的数字为\(1\)的值,将原值与其异或后就可以求得改变后的数字

Code

x ^ (x&(-x)<<1)

\(4.\) 调手表

题意

给定\(n\)进制的手表,和一个\(k\),在任意时刻,有两个操作可以进行,\(+1\)或者\(+k\),手表只能显示\(0\sim n-1\)的数字,
在最优策略下,求出从任意时间到达其他任意时间的操作数的最大值

数据范围

\(0< k < n < 100000\)

题解

因为是\(mod\)循环,可以看做是从\(1\)\(n-1\)的所有最优方案,最小步数模型,\(bfs\)即可,所有步数的最大值即可。

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)
const int N=1e5+10;
int n,k;
int ans;
int dist[N];
void bfs(){
    memset(dist,-1,sizeof dist);
    queue< int > q;
    q.push(0);
    dist[0]=0;
    while(q.size()){
        int t=q.front();
        q.pop();

        int tx=(t+1)%n,ty=(t+k)%n;

        if(dist[tx]==-1){
            dist[tx]=dist[t]+1;
            ans=max(ans,dist[tx]);
            q.push(tx);
        }
        if(dist[ty]==-1){
            dist[ty]=dist[t]+1;
            ans=max(ans,dist[ty]);
            q.push(ty);
        }
    }
}
int main(){
    scanf("%d%d",&n,&k);
    bfs();
    cout<<ans<<endl;
}

\(5.\) 搭积木

题意

输入一个\(n,m\),之后输入\(n\)行,每行\(m\)个字符表示当前是否可以放置,如果为\(.\)则可以放置,如果为\(X\)则不能放置,积木的放置必须满足以下三个规则,

  • 当前可以防止积木当且仅当当前位置上一行放置了积木

  • 每一行中积木的放置必须是连续的

默认第\(0\)行已经全部放置,求有多少种可能的放置方案,答案\(mod\; 10^{9}+7\)

数据范围

\(1\leq n,m\leq 10^{5}\)

题解

  • 状态表示: \(dp[i][l][r]\)在第\(i\)层的\(l\sim r\)区间都放上积木的方案数

    • \(l\sim r\)中能放上积木当且仅当\(i-1\)层中\(l\sim r\)都已经放上了积木,否则就为\(0\)

    • 当前行相同的放置,之前的行只要有不同的放置就算是不同的方案

  • 状态转移:\(dp[i][l][r] = \sum_{j=1}^{l} \sum_{k=r}^{m} dp[i-1][j][k]\)

    • 当前的状态计算中不包含都不放的方案,所以答案的初始值需要设置为\(1\)

Code

#include<iostream>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define ll long long
const int mod=1000000007,N=110;

char g[N][N];
ll s[N][N],dp[N][N][N];
int c[N][N];
int n,m;
int ans;

void add_suffix(int i){
    rep(j,1,m) rep(k,1,m){
        s[j][k]=s[j-1][k]+s[j][k-1]-s[j-1][k-1]+dp[i][j][k];
    }
}
ll get_suffix(int x1,int y1,int x2,int y2){
    return (s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1])%mod;
}
int main(){
    cin>>n>>m;
    per(i,n,1) scanf("%s",g[i]+1);
    rep(i,1,n)
        rep(j,1,m)
            c[i][j]=c[i][j-1]+(g[i][j]=='X');

    dp[0][1][m]=1;
    add_suffix(0);
    int res=1;
    rep(i,1,n){
        rep(j,1,m){
            rep(k,j,m){
                if(c[i][k]-c[i][j-1]==0){
                    ll &x=dp[i][j][k];
                    x=(x+get_suffix(1,k,j,m))%mod;
                    res=(res+x)%mod;
                }
            }
        }
        add_suffix(i);
    }

    // rep(i,1,n){
    //     rep(j,1,m){
    //         cout<<dp[i][j]<<' ';
    //     }
    //     cout<<endl;
    // }
    cout<<(res+mod)%mod<<endl;
}

\(6.\) 矩阵求和

题意

给定一个\(n\),矩阵的每个位置\((i,j)\)元素值等于\(gcd(i,j)\),求\(n\times n\)的矩阵的元素值之和

数据范围

\(1\leq n\leq 10^{7}\)

题解

最大公约数\(d\)的范围为\(1\leq n\)

  • 对于\(i,j \in [d,n],gcd(i,j)=d\)的个数

  • \(i,j\in [1,\lfloor \frac{n}{d} \rfloor],gcd(i,j)=1\)的数对的个数是一一对应的

  • 满足\(i<j\),且\(gcd(i,j)=1\)的数对个数即\(\sum_{x=2}^{j} \phi(x) + 1\)

  • \(i>j\)时候个数上同\(i<j\)一样,二者都包含了\((1,1)\)容斥掉即可

对于\(i\in [1,i-1]\)中与其互质的数的个数即欧拉函数\(\phi (i)\)

Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
const int N=1e7+10,mod=1e9+7;


ll phi[N];
ll s[N];
bool st[N];
int primes[N],cnt;
void get_eulers(int n){
    phi[1]=1;
    for (int i = 2; i <=n ; ++i) {
        if(!st[i]) {
            primes[cnt++]=i;
            phi[i]=i-1;
        }
        for (int j = 0; primes[j] <=n/i ; ++j) {
            st[primes[j]*i]=true;
            if(i%primes[j]==0) {
                phi[primes[j]*i]=primes[j]*phi[i];
                break;
            }
            phi[primes[j]*i]=phi[i]*(primes[j]-1);
        }
    }

    s[1]=phi[1];
    rep(i,2,n) s[i]=(s[i-1]+phi[i]*2)%mod;
}
// void get_eulers(int n){
//     rep(i,2,n) phi[i]=0;
//     phi[1]=1;
//     for(int i=2;i<=n;i++){
//         if(!phi[i]){
//             for(int j=i;j<=n;j+=i){
//                 if(!phi[j]) phi[j]=j;
//                 phi[j]=phi[j]/i*(i-1);
//             }
//         }
//     }
//     s[1]=phi[1];
//     rep(i,2,n) s[i]=(s[i-1]+phi[i]*2)%mod;
// }
int main(){
    int n;
    cin>>n;
    get_eulers(n);
    ll ans=0;
    rep(d,1,n) ans=(ans+s[n/d]*d%mod*d)%mod;
    cout<<ans<<endl;
}   
posted @ 2020-10-25 14:38  Hyx'  阅读(10)  评论(0编辑  收藏  举报