Hihocoder [Offer收割]编程练习赛70 解题报告 By cellur925

并没有第四题。(还不会矩阵乘法加速线性数列)

题目1 : 数位翻转

时间限制:20000ms
单点时限:1000ms
内存限制:256MB

描述

给定一个数 n,你可以进行若干次操作,每次操作可以翻转 n 的二进制表示下的某一位,即将 0 变成 1,1 变成 0

现在小 Hi 想知道,至少需要多少次操作,才能将 n 变成 n-1

输入

一个正整数 n

1 ≤ n ≤ 109

输出

输出最少的操作次数

签到题,模拟一下取出各位二进制数即可,极水,怒A。

 1 #include<cstdio>
 2 #include<algorithm> 
 3 
 4 using namespace std;
 5 
 6 int n,m,lena,lenb,ans;
 7 int a[50],b[50];
 8 
 9 int main()
10 {
11     scanf("%d",&n);
12     m=n-1;
13     while(n)
14     {
15         a[++lena]=n%2;
16         n/=2;
17     }
18     while(m)
19     {
20         b[++lenb]=m%2;
21         m/=2;
22     }
23     int len=max(lena,lenb);
24     for(int i=1;i<=len;i++)
25      if(a[i]!=b[i]) ans++;
26     printf("%d",ans);
27     return 0;
28 }
View Code

题目2 : 最短公共子序列

时间限制:20000ms
单点时限:1000ms
内存限制:256MB

描述

给定一个 01 串 A,你需要找一个和它等长的01串 B,使得 A 和 B 的最长公共子序列最短

为了方便,你不需要输出 B,你只需要输出 A 和 B 的最长公共子序列的长度

输入

第一行一个 01 串 A

1 ≤ |A| ≤ 105

输出

输出最短的长度

样例输入
000111
样例输出
3


这个题啊,看起来有点唬人。一看到“最长公共子序列最短”,我上来就是一顿二分敲。后来发现check函数没法写,在固有的(我的)惯性思维中,把带字符串背景的都考虑成公共子串(中间不能有不同),而本题恰好反其道而行之,问子序列(子序列中间可间隔不同的)。

我们再冷静分析一下,状态要么是0,要么是1,手动模拟几组答案,可以发现答案正是A串中出现最少元素的个数。

抱着试试看的心态交了上去,竟然A了。qwq。
 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 
 5 using namespace std;
 6 
 7 char py[100090];
 8 int c,d,ans;
 9 int a[100090],b[100090];
10 
11 int main()
12 {
13     scanf("%s",py+1);
14     int len=strlen(py+1);
15     for(int i=1;i<=len;i++) a[i]=(int)py[i]-'0'; 
16     for(int i=1;i<=len;i++)
17      if(a[i]==1) c++;else d++;
18     ans=min(c,d);
19     printf("%d",ans);
20     return 0;
21 }
View Code

题目3 : 拼三角形

时间限制:20000ms
单点时限:1000ms
内存限制:256MB

描述

给定 n 根木棍,第 i 根长度为 ai

现在你想用他们拼成尽量多的面积大于 0 的三角形,要求每根木棍只能被用一次,且不能折断

请你求出最多能拼出几个

输入

第一行一个正整数 n

第二行 n 个正整数 a1 … an

1 ≤ n ≤ 15

1 ≤ ai ≤ 109

输出

输出最多能拼出几个三角形

学长表示:一道暴搜题!巧了!我就不会写暴搜!qwq!

再和学长学习一下qwq。

由于最多有15根棒,所以顶多也就5个三角形。

然后我们就搜就行了qwq。我的模拟&贪心只能拿75分。

注释写在码里qwq。

#include<cstdio>
#include<algorithm>

using namespace std;
typedef long long ll;

int n;
ll ans;
int a[30];
bool flag[30];

void dfs(int cnt,int a1,int a2,int pre)
{//cnt->当前已经选到第几个三角形
//a1->三角形中最短边,a2->三角形中最长边。
//pre->上一个选到哪了(下标)
    if(cnt==ans+1)
    {
        printf("%d",ans);
        exit(0);//void函数中想直接return 0结束程序用exit
    }
    if(!a1)
    {
        for(int i=pre+1;i<=n;i++)
        {
            if(flag[i]) continue;
            flag[i]=1;
            dfs(cnt,a[i],0,i);
            flag[i]=0;
        }
    }
    else if(a1>0&&a2<=0)
    {
        for(int i=pre+1;i<=n;i++)
        {
            if(flag[i]) continue;
            flag[i]=1;
            dfs(cnt,a1,a[i],i);
            flag[i]=0;
        }
    }
    else 
    {
        for(int i=pre+1;i<=n;i++)
        {
            if(flag[i]) continue;
            if(a1+a2<=a[i]) return ;
            flag[i]=1;
            dfs(cnt+1,0,0,0);
            flag[i]=0;
        }
    }
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    sort(a+1,a+1+n);
    for(int i=n/3;i>=0;i--)
    {
        ans=i;//要几个 当前在哪 现在已经有几个边 
        dfs(1,0,0,0);
    }
    printf("%d",ans);
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/nopartyfoucaodong/p/9386726.html