洛谷 P4749 - [CERC2017]Kitchen Knobs(差分转换+dp,思维题)
一道挺有意思的思维题。
首先有一个 obvious 的结论,就是对于每个炉子,要么转到哪里都符合条件,要么存在唯一的最大值。对于转到哪儿都符合条件的炉子我们 duck 不必考虑它,故我们只用考虑存在唯一最大值的炉子即可,我们记 \(a_i\) 表示第 \(i\) 个炉子需顺时针旋转多少次才能到达火力最大的位置,那么对一个区间 \([l,r]\) 进行逆时针旋转 \(c\) 格的操作就等价于令 \([l,r]\) 中的 \(a_i\) 在模 \(7\) 意义下全部加 \(c\),我们要求最少多少次操作才能将其全变为 \(0\)。
这里涉及区间加,因此套路地考虑差分,记差分序列为 \(b\),那么一个区间 \(+c\) 即可转化为两个单点加。乍一看还是不太好做,不过注意如果我们考虑在每次选择的两个点 \(x,y\) 中连一条边,那么最终会得到一张 \(cnt\) 条边的图,其中 \(cnt\) 为操作次数。显然每次单点加操作并不改变 \(b\) 数组的和,而对于图中的每个连通块,该连通块中的点最终的 \(b_i\) 之和为 \(0\),故一开始他们 \(b_i\) 的和也是 \(0\),因此我们可以将题目转化为,将所有 \(b_i\) 划分为尽可能多的组,满足每组的和模 \(7\) 余 \(0\),答案就是 \(n-\)划分次数。
这个划分次数怎么求呢?我们首先求出 \(cnt_v\) 表示有多少个 \(b_i=v\),首先 \(0\) 肯定是单独成一组的,产生 \(cnt_0\) 的贡献,接下来我们肯定希望划分出大小为 \(2\) 的组,而大小为 \(2\) 的组肯定只能由 \((1,6),(2,5),(3,4)\) 配对得到,这样两两配对又能产生一些贡献,配完对后就只剩下三种数 \(x,y,z\) 了,此时可以直接 \(dp_{i,j,k}\) 表示还剩 \(i\) 个 \(x\),\(j\) 个 \(y\),\(k\) 个 \(z\) 最多可以划分为多少组,转移 \(\mathcal O(1)\),总复杂度 \(\dfrac{n^3}{27}\),跑得飞快(
const int MAXN=501;
int n,m,a[MAXN+5],cnt[7],ans=0,dp[MAXN+5][MAXN+5][MAXN+5];
pair<int,int> clr(int x,int y){
return (cnt[x]>cnt[y])?(ans+=cnt[y],mp(x,cnt[x]-cnt[y])):(ans+=cnt[x],mp(y,cnt[y]-cnt[x]));
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
string s;cin>>s;bool flg=0;
for(int j=0;j<7;j++) if(s[j]!=s[0]) flg=1;
if(!flg) continue;
vector<pair<string,int> > vec;
for(int j=0;j<7;j++){
string str;
for(int k=j,stp=0;stp<7;stp++,k=(k+1)%7) str=str+s[k];
vec.pb(mp(str,j));
} sort(vec.begin(),vec.end());
reverse(vec.begin(),vec.end());
a[++m]=vec[0].se;
}
for(int i=m;i;i--) a[i]=(a[i]-a[i-1]+7)%7,cnt[a[i]]++;
ans=cnt[0];
pair<int,int> p1=clr(1,6);
pair<int,int> p2=clr(2,5);
pair<int,int> p3=clr(3,4);//printf("%d\n",ans);
// printf("%d %d %d\n",p1.fi,p2.fi,p3.fi);
// printf("%d %d %d\n",p1.se,p2.se,p3.se);
for(int i=0;i<=p1.se;i++) for(int j=0;j<=p2.se;j++) for(int k=0;k<=p3.se;k++){
chkmax(dp[i+1][j][k],dp[i][j][k]+!(((i+1)*p1.fi+j*p2.fi+k*p3.fi)%7));
chkmax(dp[i][j+1][k],dp[i][j][k]+!((i*p1.fi+(j+1)*p2.fi+k*p3.fi)%7));
chkmax(dp[i][j][k+1],dp[i][j][k]+!((i*p1.fi+j*p2.fi+(k+1)*p3.fi)%7));
} printf("%d\n",m-(ans+dp[p1.se][p2.se][p3.se]));
return 0;
}
洛谷 P4749 - [CERC2017]Kitchen Knobs(差分转换+dp,思维题)的更多相关文章
- 洛谷 P2622 关灯问题II(状压DP入门题)
传送门 https://www.cnblogs.com/violet-acmer/p/9852294.html 题解: 相关变量解释: int n,m; ];//a[i][j] : 第i个开关对第j个 ...
- 洛谷T44252 线索_分治线段树_思维题
分治线段树,其实就是将标记永久化,到最后再统一下传所有标记. 至于先后顺序,可以给每个节点开一个时间戳. 一般地,分治线段树用于离线,只查询一次答案的题目. 本题中,标记要被下传 222 次. Cod ...
- BZOJ5259/洛谷P4747: [Cerc2017]区间
BZOJ5259/洛谷P4747: [Cerc2017]区间 2019.8.5 [HZOI]NOIP模拟测试13 C.优美序列 思维好题,然而当成NOIP模拟题↑真的好吗... 洛谷和BZOJ都有,就 ...
- 洛谷P1067 多项式输出 NOIP 2009 普及组 第一题
洛谷P1067 多项式输出 NOIP 2009 普及组 第一题 题目描述 一元n次多项式可用如下的表达式表示: 输入输出格式 输入格式 输入共有 2 行 第一行 1 个整数,n,表示一元多项式的次数. ...
- [洛谷P3948]数据结构 题解(差分)
[洛谷P3948]数据结构 Description 最开始的数组每个元素都是0 给出n,opt ,min,max,mod 在int范围内 A: L ,R ,X 表示把[l,R] 这个区间加上X(数组的 ...
- 洛谷P3275 [SCOI2011]糖果(差分约束,最长路,Tarjan,拓扑排序)
洛谷题目传送门 差分约束模板题,等于双向连0边,小于等于单向连0边,小于单向连1边,我太蒻了,总喜欢正边权跑最长路...... 看遍了讨论版,我是真的不敢再入复杂度有点超级伪的SPFA的坑了 为了保证 ...
- 洛谷CF809C Find a car(数位DP)
洛谷题目传送门 通过瞪眼法发现,\(a_{i,j}=(i-1)\text{ xor }(j-1)+1\). 二维差分一下,我们只要能求\(\sum\limits_{i=0}^x\sum\limits_ ...
- 洛谷 P6276 - [USACO20OPEN]Exercise P(组合数学+DP)
洛谷题面传送门 废了,又不会做/ll orz czx 写的什么神仙题解,根本看不懂(%%%%%%%%% 首先显然一个排列的贡献为其所有置换环的乘积.考虑如何算之. 碰到很多数的 LCM 之积只有两种可 ...
- 洛谷CF264D Colorful Stones(子序列匹配,思维)
洛谷题目传送门 神仙思维题. 对于两个字符串的匹配问题,似乎之前蒟蒻写的HAOI2010最长公共子序列题解中提到的建网格图模型是一种套路? 给一个稍微强一点的样例(把字母换成了ABC) AABCB B ...
随机推荐
- JavaScript05
显示和隐藏 元素的显示和隐藏 元素display属性可控制元素的显示和隐藏,先获取元素对象,再通过点语法调用style对象中的display属性 语法格式: 元素.style.display='non ...
- Selenium获取动态图片验证码
Selenium获取动态图片验证码 关于图片验证码的文章,我想大家都有一定的了解了. 在我们做UI自动化的时候,经常会遇到图片验证码的问题. 当开发不给咱们提供万能验证码,或者测试第三方网站比如知乎的 ...
- Golang通脉之类型定义
自定义类型 在Go语言中有一些基本的数据类型,如string.整型.浮点型.布尔等数据类型, Go语言中可以使用type关键字来定义自定义类型. type是Go语法里的重要而且常用的关键字,type绝 ...
- 【c++ Prime 学习笔记】第8章 IO库
C++语言不直接处理输入输出,而是通过标准库中的一组类来处理IO 1.2节介绍的IO库: istream(输入流)类型,提供输入 ostream(输出流)类型,提供输出 cin,是istream对象, ...
- Codeforces Round #747 (Div. 2) Editorial
Codeforces Round #747 (Div. 2) A. Consecutive Sum Riddle 思路分析: 一开始想起了那个公式\(l + (l + 1) + - + (r − 1) ...
- NOIP模拟86(多校19)
T1 特殊字符串 解题思路 \(f_{i,j}\) 表示前 \(i\) 个字符中结尾为 \(j\) 的最大贡献. 转移枚举当前位置于之前位置结尾的组合加上贡献即可. 对于边界问题,容易发现选择 1 一 ...
- 翻转子串 牛客网 程序员面试金典 C++ Python
反转子串 牛客网 程序员面试金典 C++ Python 题目描述 假定我们都知道非常高效的算法来检查一个单词是否为其他字符串的子串.请将这个算法编写成一个函数,给定两个字符串s1和s2,请编写代码检查 ...
- Ubuntu virtualenv 创建 python2 虚拟环境 激活 退出
首先默认安装了virtualenv 创建python2虚拟环境 your-name@node-name:~/virtual_env$ virtualenv -p /usr/bin/python2 py ...
- 前端面试手写代码——JS数组去重
目录 1 测试用例 2 JS 数组去重4大类型 2.1 元素比较型 2.1.1 双层 for 循环逐一比较(es5常用) 2.1.2 排序相邻比较 2.2 查找元素位置型 2.2.1 indexOf ...
- 微服务(七)Gateway服务网关
1 为什么要有网关 权限控制:网关作为微服务入口,需要校验用户是是否有请求资格,如果没有则进行拦截. 路由和负载均衡:一切请求都必须先经过gateway,但网关不处理业务,而是根据某种规则,把请求转发 ...