洛谷 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;
}

浙公网安备 33010602011771号