首页 > 其他分享 >#9134.反转eehniy

#9134.反转eehniy

时间:2023-10-15 20:58:56浏览次数:33  
标签:le 20 9134 int 反转 一段 eehniy 操作

blog


题面

yinhee 去面试 Google 总裁。

面试官给他了一个长度为 \(n\) 的 \(01\) 串。

面试官给他以下两种操作是的这个序列前 \(n-m\) 个数字与后 \(n-m\) 个数字匹配。具体地说就是让

\[a_1 = a_{m+1} \cdots a_{n - m} = a_n \]

  1. 选择其中的一个数,将其反转(即为从 \(0\) 变成 \(1\))

  2. 反转前 \(k \times m\) 个数(\(k\) 为自己设定)

所以到底最少要多少次呢?

yinhee 只需要最少的翻转次数就能满足面试官的要求了。

其中保证 \(1 \le n,m \le 300\)。


我们可以考虑一些简单的情况,比如 \(m = 1\)。

容易发现操作 \(1\) 和操作 \(2\) 的顺序不影响结果,所以我们可以假定所有操作 \(1\) 都在操作 \(2\) 之前。

而接在操作 \(1\) 后面的操作 \(2\) 的数量即为 \((\text{连续栓的数量} - 1)\)。

然后我们考虑 \(m > 1\) 的情况。

显然最后序列上每 \(m\) 长度分一段,则每一段都相同,最后一段例外,是和其他段的一段等长前缀相同。

那么设最后每一段的状态都为 \(S\)。

一开始每段的状态为 \(e_i\) ,则在所有操作 2 之前,都有 \(S = e_i\) 或 \(S = flip(e_i)\)。\(flip(x)\) 表示把 \(x\) 串内所有数反转。

然后定义一个序列 \(c_i\) 表示第 \(i\) 段有没有被 \(flip\)。

然后考虑 DP,但是发现行不通,怎么定义都好像会有后效性。

但是我们可以考虑每 \(m\) 个一段,那么就会有 \(\left \lceil \dfrac{n}{m} \right \rceil\) 段。

结合 \(n \le 300\),发现 \(\sqrt n \le 20\)。所以可以根号分治!!

  • \(m \le \sqrt n\)

既然这样,那么段数必然少于 \(20\),暴力状压即可。

对于每一种状态我们考虑 \(dp_{i,0/1}\) 表示当前处理到第 \(i\) 段没有反转的最小次数。

所以就可以写出这一段的代码了。

#define popcount(x) __builtin_popcount(x)
void solve1()
{
    for(int i = 1;i <= n / m + 1;i++)
    {
        for(int j = 0;j < m;j++)
        {
            c[i] |= e[(i - 1) * m + j + 1] << j;//计算c[i]的值
        }
    }
    int k = 1 << m;
    int ans = 0x3f3f3f3f;
    for(int i = 0;i < k;i++)
    {
        memset(dp,63,sizeof(dp));
        dp[0][0] = 0;
        for(int j = 1;j <= n / m;j++)
        {
            for(int l = 0;l <= 1;l++)
            {
                dp[j][l] = min(dp[j - 1][l] + popcount(i ^ c[j] ^ (l * (k - 1))),dp[j - 1][l ^ 1] + popcount(i ^ c[j] ^ (l * (k - 1))) + 1);
            }
        }
        if(n % m == 0)
        {
            ans = min({ans,dp[n / m][1],dp[n / m][0]});
        }
        else
        {
            int tmp = (1 << (n % m)) - 1;
            int x = i & tmp;
            for(int j = 0;j <= 1;j++)
            {
                dp[n / m + 1][j] = min(dp[n / m][j] + popcount(x ^ c[n / m + 1] ^ (j * tmp)),dp[n / m][j ^ 1] + popcount(i ^ c[n / m + 1] ^ (j * tmp)) + 1);
            }
            ans = min({ans,dp[n / m + 1][1],dp[n / m + 1][0]});
        }//最后一段需要单独处理
    }
    cout << ans << '\n';
}//dp,O((2^sqrt(n))*n)

\(j \times (2^m - 1)\) 是看这一段有没有反转。

注意最后一段要单独处理。

  • \(m > \sqrt n\)

那么段数是 \(\le 20\) 的。

于是我们可以状压 \(c\) 然后处理状态。

然后我们可以根据每一段相同的位的 \(0/1\) 数量,贪心的选择改的最少的方案即可。

最后需要加上 \(2\) 的操作次数。所有的情况去取个最小就是答案。

void solve2()
{
    int k = 1 << ((n - 1) / m);
    int ans = 0x3f3f3f3f;
    for(int i = 0;i < k;i++)
    {
        int sum = 0;
        memset(cnt,0,sizeof(cnt));
        for(int j = 1;j <= (n - 1) / m;j++)
        {
            sum += ((i >> j) & 1) ^ ((i >> (j - 1)) & 1);
        }
        for(int j = 1;j <= n;j++)
        {
            cnt[j % m][e[j] ^ ((i >> ((j - 1) / m)) & 1)]++;
        }
        for(int j = 0;j < m;j++)
        {
            sum += min(cnt[j][0],cnt[j][1]);
        }
        ans = min(ans,sum);
    }
    cout << ans << '\n';
}

其中 \(cnt_{j,0/1}\) 表示每一段中第 \(j\) 位为 \(0/1\) 至少要修改多少个。


最终的code

标签:le,20,9134,int,反转,一段,eehniy,操作
From: https://www.cnblogs.com/Carousel/p/17766152.html

相关文章

  • 面试必刷TOP101:2、链表内指定区间反转
    一、题目将一个节点数为size链表m 位置到n位置之间的区间反转,要求时间复杂度O(n),空间复杂度O(1)。例如:importjava.util.*;/**publicclassListNode{*intval;*ListNodenext=null;*}*/publicclassSolution{/****@paramhea......
  • 面试必刷TOP101:1、反转链表
    一、题目给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。示例:输入:{1,2,3}返回值:{3,2,1}二、题解2.1使用栈求解栈是先进后出的。实现原理就是把链表节点一个个入栈,当全部入栈完之后再一个个出栈,出栈的时候在把出栈的结点......
  • #9134. 翻转硬币 题解
    首先考虑一些简单的情况,比如\(m=1\)。容易发现操作1和操作2的顺序不会影响结果,于是可以钦定所有操作1在操作2之前。并且可以发现,进行完所有1后2的次数即为\((\text{连续段个数}-1)\)。然后考虑将\(m>1\)的情况。显然最后序列上每\(m\)长度分一段,则每一段都相......
  • 力扣刷题笔记-07 整数反转
    07整数反转狗看了都摇头的年纪,纯爱战士一败涂地。怎么反转temp用来保存个位数res用来保存当前结果123,取模运算,这样就可以获得最后一位。比如对123%10,得到temp=3.判断res是不是溢出(重点)如果没有溢出,res扩大十倍,再加上个位数,就相当于是反转了。res=res*10+temp;返回......
  • 151. 反转字符串中的单词
    LeetCode题目:https://leetcode.cn/problems/reverse-words-in-a-string/description/classSolution{public:voidreverse(string&s,intstart,intend){//翻转,区间写法:左闭右闭[]for(;start<end;start++,end--){swap(s[start],s[end]......
  • PAT乙级真题:1110 区块反转
     【1110区块反转分值:25乙级】题目描述:给定一个单链表 L,我们将每 K 个结点看成一个区块(链表最后若不足 K 个结点,也看成一个区块),请编写程序将 L 中所有区块的链接反转。例如:给定 L 为1→2→3→4→5→6→7→8,K 为3,则输出应该为7→8→4→5→6→1→2→3 ......
  • 随想录Day8|344. 反转字符串、541. 反转字符串Ⅱ、LCR 122. 路径加密、151. 反转字符
    随想录Day8|344.反转字符串、541.反转字符串Ⅱ、LCR122.路径加密、151.反转字符串里的单词、LCR182.动态口令 题目越来越长了…… 344.反转字符串文章&视频讲解编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组s的形式给出。不要给另外的数......
  • 数组反转以及二位数组
    数组反转就是新生成一个数组,来反向接受原数组位置的数据publicstaticint[]reverse(int[]array){int[]reverse=newint[]array.length;for(inti=0,j=array.lenhth;i<array.length;i++,j--){ reverse[j]=array[i];}returnreverse;}假如遍历数组并输出的函数pri......
  • 203.移除链表元素 707.设计链表 206.反转链表
    203.移除链表元素力扣题目链接(opensnewwindow)题意:删除链表中等于给定值val的所有节点。示例1:输入:head=[1,2,6,3,4,5,6],val=6输出:[1,2,3,4,5]示例2:输入:head=[],val=1输出:[]示例3:输入:head=[7,7,7,7],val=7输出:[]思路操作链表的两种方式:直接使用原来的......
  • Spring框架中 依赖注入和控制反转,最简单、最通俗的解释! 再加上一个AOP
    首先依赖注入==控制反转,只不过控制反转这个词汇,让人产生了错误的理解,才使用新的词汇:依赖注入来替换到这个词汇。“依赖注入”是指一个对象应用另外一个对象来提供一个特殊的能力。例如,把一个数据库连接以参数的形式传到一个对象的结构方法里,而不是在那个对象内部自行创......