1.2 SMU Winter 2023 蓝桥杯模拟赛 1

题意:给n,使满足式子a+b/c=n,其中a,b,c共同恰好由1,2...9组成,求a,b,c的取值种数

思路1:枚举出9个数的全排列(可使用next_permutation() ),再用两重循环暴力分解出三段,每段分别代表a,b,c,若满足式子则计数

注意:判断b/c是否为整除

 1 int main(){
 2     int n,a[10]={0,1,2,3,4,5,6,7,8,9},ans;
 3     cin>>n;
 4     while(1){
 5         int x=0;
 6         for(int i=1;i<=7;++i){
 7             x=x*10+a[i];
 8             int y=0;
 9             for(int j=i+1;j<=8;++j){
10                 y=y*10+a[j];
11                 int k=0;
12                 for(int u=j+1;u<=9;++u){
13                     k=k*10+a[u];
14                 }
15                 if(y%k==0&&x+y/k==n){
16                         ans++;
17                 }
18             }
19         }
20         next_permutation(a+1,a+10);
21 
22 //判断全排列是否重复
23 
24         int ok=0;
25         for(int i=1;i<=9;++i){
26             if(a[i]!=i){
27                 ok=1;
28                 break;
29             }
30         }
31         if(!ok)break;
32     }
33     cout<<ans;
34     return 0;
35 }

 

思路2:式子转换为 n * c =a * c +b ,先枚举a,对于每个a再枚举c,则可通过式子求b,再判断b是否符合

const int N=520;
int had_use[N],cp[N];
int ans=0;
int n;
bool check(int a,int c)
{
    int b = n * c - a * c;

    if(!a||!b||!c)return false;

    memcpy(cp,had_use,sizeof had_use);//防改变已用数字
    while(b)
    {
        int t=b%10;
        b/=10;
        if(!t||cp[t])return false;//b是否含0以及与已用数字重复
        cp[t]=1;
    }
    for(int i=1;i<=9;i++)//是否用完9个数
      if(!cp[i])
      return false;

   return true;
}

void dfs_c(int x,int a,int c)
{
    if(x>9)return;
    if(check(a,c))ans++;
    for(int i=1;i<=9;i++)
      if(!had_use[i])
      {
          had_use[i]=1;
          dfs_c(x+1,a,c*10+i);//枚举c的下一层
          had_use[i]=0;//用完还原
      }
}
void dfs_a(int x,int a)
{
    if(a>=n)return;
    if(a)dfs_c(x,a,0);//枚举c,分别表示:已用数目,a的值,c的值

    for(int i=1;i<=9;i++)//枚举当前位置的可用数字
      if(!had_use[i])
      {
          had_use[i]=1;
          dfs_a(x+1,a*10+i); //枚举a的下一层
          had_use[i]=0;//用完还原
      }
}
int main()
{
    cin>>n;
    dfs_a(0,0);//分别表示:已经用了多少个数字 , 当前的a的值
    cout<<ans;
    return 0;
}

 

题意:在若干连续的数中,找出一个缺少的数和一个重复的数

思路:将所有数排序后枚举一边

注意:读入若干数据可用 while(cin>>x) 或 while(scanf("%d",&x)!=EOF)

 1 int main(){
 2     int n,x,a[100005],e,f;
 3     cin>>n;
 4     while(cin>>x)a[x]++;
 5     for(int i=1;;++i){
 6         if(a[i-1]&&a[i+1]&&!a[i])e=i;
 7         if(a[i]>1)f=i;
 8         if(e&&f)break;
 9     }
10     cout<<e<<' '<<f;
11     return 0;
12 }

 

 

题意:给出两个由两个字符组成的等长字符串,求a串变b串的最小操作数,每次操作翻转相邻的两个字符

思路:由题可知,出现不同的次数一定为偶数,保证操作数最小,找出依次出现的两个不同位置即可

 1 int main(){
 2     char a[1005],b[1005];
 3     int c[1005]={0},k=1,s=0;
 4     cin>>a+1>>b+1;
 5     for(int i=1;a[i];++i){
 6         if(a[i]!=b[i])c[k++]=i;
 7     }
 8     for(int i=1;c[i];++i)
 9     {
10         if(i%2)s-=c[i];
11         else s+=c[i];
12     }
13     cout<<s;
14     return 0;
15 }

 

题意:a1~an中对[2,n-1]中任意的数进行aiai ,ai+1​ )aiai​ ,a​,ai+ai​ ),使amax最小

思路:每对 a进行一次操作等同于将前缀和 si 与 si-1 进行交换,要使得amax最小,即前缀和之差的最大值最小,需使 s[ ] 尽可能单调排列,且需考虑s[n]固定,可以外加s[0]也固定,将问题转化为一个数组内除首位以外都可任意排序,通过画图可知有两个拐点的曲线重叠部分最小时,单调部分最多,该曲线满足:1.左端点小于右端点 2.极小值在极大值左边

 

 1 typedef long long LL;
 2 const int N = 3e5 + 10;
 3 int t, n;
 4 LL s[N], a[N];
 5 bool v[N];
 6 int main()
 7 {
 8     cin >> t;
 9     while (t--)
10     {
11         cin >> n;
12         memset(v, 0, sizeof v);
13         for (int i = 1; i <= n; i++)
14             cin >> s[i], s[i] += s[i - 1];
15 
16         LL s0 = s[0], sn = s[n];
17         if (s0 > sn)
18             swap(s0, sn);
19         sort(s, s + n + 1);
20 
21         for (int i = 0; i <= n; i++)
22             if (s[i] == s0)
23             {
24                 s0 = i;
25                 break;
26             }
27         for (int i = n; i >= 0; i--)
28             if (s[i] == sn)
29             {
30                 sn = i;
31                 break;
32             }
33         int l = 0, r = n;
34         for (int i = s0; i >= 0; i -= 2)
35         {
36             a[l++] = s[i];
37             v[i] = 1;
38         }
39         for (int i = sn; i <= n; i += 2)
40         {
41             a[r--] = s[i];
42             v[i] = 1;
43         }
44         for (int i = 0; i <= n; i++)
45             if (!v[i])
46                 a[l++] = s[i];
47         LL res = 0;
48         for (int i = 1; i <= n; i++)
49             res = max(res, abs(a[i] - a[i - 1]));
50         cout << res << endl;
51     }
52     return 0;
53 }

 

题意:用 n个+ 和 m个 -  和 n+m+1 个数 构成一个值最大的后缀表达式

思路:最大值为 max + ( {...} ) - ( min  {...} );若没有‘-’,最大值即为全部数的和;若有‘-’,只需减去最小的数和加上最大的数,再加上剩余数的绝对值即可;

int main(){
    int n,m,a[200010],tmp[200010];
    cin>>n>>m;
    for(int i=0;i<m+n+1;++i)
        cin>>a[i];
    long long s=0;
    if(!m){
        for(int i=0;i<m+n+1;++i)
            s+=a[i];
        cout<<s;
    }
    else{
        sort(a,a+m+n+1);
        for(int i=0;i<m+n+1;++i){
            if(i==0)s-=a[i];
            else if(i==m+n)s+=a[i];
            else
                s+=abs(a[i]);
        }
        cout<<s;
    }
    return 0;
}

 

题意:给出n个数,求包含这n个数的等差数列的最小长度

思路:公差越大,长度越小;排列后,由于每个数与第一个数的差都为公差的倍数,枚举求出最大公差,由公式(An - A1)/公差 +1 求出最小长度,当公差为0时最小长度即为n

int gcd(int a,int b){
    if(b==0)return a;
    return gcd(b,a%b);
}
int main(){
    int n,a[100005],d;
    cin>>n;
    for(int i=0;i<n;++i)
        cin>>a[i];
    sort(a,a+n);
    for(int i=0;i<n;++i){
        if(i==1)d=a[i]-a[0];
        else if(i>1) d=gcd(d,a[i]-a[0]);
    }
    if(!d)cout<<n;
    else cout<<(a[n-1]-a[0])/d+1;
    return 0;
}

 

题意:求1~n中所有包含2,0,1,9(不含前缀0)的数的和

思路:一一枚举

 1 bool check(int x){
 2     if(x==2||x==0||x==1||x==9)
 3         return true;
 4     return false;
 5 }
 6 int main(){
 7     cin.tie(0),cout.tie(0);
 8     int n,s=0;
 9     cin>>n;
10     for(int i=1;i<=n;++i){
11         if(i<10){
12             if(check(i))s+=i;
13         }
14         else{
15             int y=i,k=1;
16             while(y/10){
17                 if(check(y%10)){
18                     s+=i;k=0;break;
19                 }
20                 y/=10;
21             }
22             if(k&&(y==2||y==1||y==9))s+=i;
23         }
24     }
25     cout<<s;
26     return 0;
27 }

 

题意:给出一颗包含n个节点的完全二叉树,问哪一层的权值之和最大

思路:枚举,2h-1作为分段点求和

 

 1 int main(){
 2     long long s,ma=-1e18,n,a[100005];
 3     cin>>n;
 4     for(int i=1;i<=n;++i)
 5         cin>>a[i];
 6     int h=1,res=1;
 7     for(int i=1;i<=n;i*=2){
 8         s=0;
 9         for(int j=i;j<=i*2-1&&j<=n;++j)
10             s+=a[j];
11         if(s>ma){
12             ma=s;
13             res=h;
14         }
15         h++;
16     }
17     cout<<res;
18     return 0;
19 }

 

 

 
posted @ 2023-01-03 21:19  bible_w  阅读(72)  评论(0编辑  收藏  举报