cf 2000+()-其他
cf 2000+()
D2. Zero-One (Hard Version) 2000 好dp
https://codeforces.com/problemset/problem/1733/D2
题解:
首先取c[i]=a[i]xorb[i],若为1数为odd则无解,否则
1,当x>=y时
若不同数>=4显然我们可以交叉算用n/2y解决,当不同数=2时我们分类讨论,当n<=3时,只能使用x,故此时ans=x;
当n=4,若不同的两点在2,3位置,则需要花费min(3y,x)否则min(2y,x);
当n>=5时,min(2y,x)。
2,x<y时,
使用dp,关键在于确立状态,什么状态好转移,好表征关键特征?首先前i项这个阶段肯定是一维,由于和相对位置有关,故我们需要确定当前位是0/1,才能转移,故另一维表示当前位为0/1,但还是有很多状态重叠,转移时还有什么会变化?前i项处理后仍不同数量,此时已可列出转移方程:
若c[i]=0,
f(0,i,j)=min(f(0,i-1,j),f(1,i-1,j));
f(1,i,j)=min(f(0,i-1,j)+y,f(1,i,j)+x,f(0,i-1,j-2)+x,f(1,i-1,j-2)+y)
若 c[i]=1,
f(1,i,j)=min(f(1,i-1,j-1),f(0,i-1.j-1));
f(0,i,j)=min(f(1,i-1,j+1)+x,f(0,i-1,j+1)+y,f(0,i-1,j-1)+x,f(1,i-1,j-1)+y)
再特判一下j=0,j=i的情况便可,答案即为f(0,n,0)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5050,mod=998244353;
int a[N],b[N],c[N],f0[N][N],f1[N][N];
void solve(){
int n,x,y;cin>>n>>x>>y;
string s;cin>>s;
for(int i=0;i<n;i++) a[i+1]=s[i]-'0';
cin>>s;
for(int i=0;i<n;i++) b[i+1]=s[i]-'0';
int cnt=0;
for(int i=1;i<=n;i++) c[i]=a[i]^b[i],cnt+=c[i];
if(cnt%2){
puts("-1");
return;
}
if(x>=y){
if(cnt==2){
int q=0,w=0;
for(int i=1;i<=n;i++){
if(c[i]==1)
if(!q) q=i;
else w=i;
}
if(abs(q-w)!=1){
cout<<y<<endl;
}
else{
if(n<=3){
cout<<x<<endl;
}
else if(n==4){
if(q==1||w==n){
cout<<min(2*y,x)<<endl;
}
else cout<<min(3*y,x)<<endl;
}
else{
cout<<min(x,2*y)<<endl;
}
}
return;
}
cout<<cnt/2*y<<endl;
return;
}
for(int i=0;i<=n;i++){
for(int j=0;j<=n;j++) f0[i][j]=f1[i][j]=1e18;
}
if(c[1]==1) f1[1][1]=0;
else f0[1][0]=0;
for(int i=2;i<=n;i++){
for(int j=0;j<=i;j++){
if(c[i]==0){
f0[i][j]=min(f0[i-1][j],f1[i-1][j]);
if(j<=1) f1[i][j]=min(f0[i-1][j]+y,f1[i-1][j]+x);
else{
f1[i][j]=min({f0[i-1][j]+y,f1[i-1][j]+x,f0[i-1][j-2]+x,f1[i-1][j-2]+y});
}
}
else{
if(j!=0)
f1[i][j]=min(f1[i-1][j-1],f0[i-1][j-1]);
if(j==0){
f0[i][j]=min(f0[i-1][j+1]+y,f1[i-1][j+1]+x);
}
else if(j==i){
f0[i][j]=min(f0[i-1][j-1]+x,f1[i-1][j-1]+y);
}
else{
f0[i][j]=min({f0[i-1][j+1]+y,f1[i-1][j+1]+x,f0[i-1][j-1]+x,f1[i-1][j-1]+y});
}
}
}
}
cout<<f0[n][0]<<endl;
}
signed main(){
int T;cin>>T;
while(T--) solve();
}
C2. Sheikh (Hard Version) 2100
https://codeforces.com/problemset/problem/1732/C2
题解:对于一个区间,其显然其sum-xor最大值为整个区间,若想缩小区间,则需从两端逐渐缩减,一个点对sum-xor无影响当且仅当其让sum和xor增加了相同的数量,即为其所有为1的位上余下的xor为0,而总共只有31位,故当删除32个数时,必有两个某一位上均为1,此时对最大值有影响。故我们可以对每一个询问,枚举合法的左端点,寻找最小右端点,复杂度至多为3131q,可以通过。
代码:略。。
D2. Zero-One (Hard Version) 2000 好dp
https://codeforces.com/problemset/problem/1733/D2
题解:
首先取c[i]=a[i]xorb[i],若为1数为odd则无解,否则
1,当x>=y时
若不同数>=4显然我们可以交叉算用n/2y解决,当不同数=2时我们分类讨论,当n<=3时,只能使用x,故此时ans=x;
当n=4,若不同的两点在2,3位置,则需要花费min(3y,x)否则min(2y,x);
当n>=5时,min(2y,x)。
2,x<y时,
使用dp,关键在于确立状态,什么状态好转移,好表征关键特征?首先前i项这个阶段肯定是一维,由于和相对位置有关,故我们需要确定当前位是0/1,才能转移,故另一维表示当前位为0/1,但还是有很多状态重叠,转移时还有什么会变化?前i项处理后仍不同数量,此时已可列出转移方程:
若c[i]=0,
f(0,i,j)=min(f(0,i-1,j),f(1,i-1,j));
f(1,i,j)=min(f(0,i-1,j)+y,f(1,i,j)+x,f(0,i-1,j-2)+x,f(1,i-1,j-2)+y)
若 c[i]=1,
f(1,i,j)=min(f(1,i-1,j-1),f(0,i-1.j-1));
f(0,i,j)=min(f(1,i-1,j+1)+x,f(0,i-1,j+1)+y,f(0,i-1,j-1)+x,f(1,i-1,j-1)+y)
再特判一下j=0,j=i的情况便可,答案即为f(0,n,0)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5050,mod=998244353;
int a[N],b[N],c[N],f0[N][N],f1[N][N];
void solve(){
int n,x,y;cin>>n>>x>>y;
string s;cin>>s;
for(int i=0;i<n;i++) a[i+1]=s[i]-'0';
cin>>s;
for(int i=0;i<n;i++) b[i+1]=s[i]-'0';
int cnt=0;
for(int i=1;i<=n;i++) c[i]=a[i]^b[i],cnt+=c[i];
if(cnt%2){
puts("-1");
return;
}
if(x>=y){
if(cnt==2){
int q=0,w=0;
for(int i=1;i<=n;i++){
if(c[i]==1)
if(!q) q=i;
else w=i;
}
if(abs(q-w)!=1){
cout<<y<<endl;
}
else{
if(n<=3){
cout<<x<<endl;
}
else if(n==4){
if(q==1||w==n){
cout<<min(2*y,x)<<endl;
}
else cout<<min(3*y,x)<<endl;
}
else{
cout<<min(x,2*y)<<endl;
}
}
return;
}
cout<<cnt/2*y<<endl;
return;
}
for(int i=0;i<=n;i++){
for(int j=0;j<=n;j++) f0[i][j]=f1[i][j]=1e18;
}
if(c[1]==1) f1[1][1]=0;
else f0[1][0]=0;
for(int i=2;i<=n;i++){
for(int j=0;j<=i;j++){
if(c[i]==0){
f0[i][j]=min(f0[i-1][j],f1[i-1][j]);
if(j<=1) f1[i][j]=min(f0[i-1][j]+y,f1[i-1][j]+x);
else{
f1[i][j]=min({f0[i-1][j]+y,f1[i-1][j]+x,f0[i-1][j-2]+x,f1[i-1][j-2]+y});
}
}
else{
if(j!=0)
f1[i][j]=min(f1[i-1][j-1],f0[i-1][j-1]);
if(j==0){
f0[i][j]=min(f0[i-1][j+1]+y,f1[i-1][j+1]+x);
}
else if(j==i){
f0[i][j]=min(f0[i-1][j-1]+x,f1[i-1][j-1]+y);
}
else{
f0[i][j]=min({f0[i-1][j+1]+y,f1[i-1][j+1]+x,f0[i-1][j-1]+x,f1[i-1][j-1]+y});
}
}
}
}
cout<<f0[n][0]<<endl;
}
signed main(){
int T;cin>>T;
while(T--) solve();
}
C2. Sheikh (Hard Version) 2100
https://codeforces.com/problemset/problem/1732/C2
题解:对于一个区间,其显然其sum-xor最大值为整个区间,若想缩小区间,则需从两端逐渐缩减,一个点对sum-xor无影响当且仅当其让sum和xor增加了相同的数量,即为其所有为1的位上余下的xor为0,而总共只有31位,故当删除32个数时,必有两个某一位上均为1,此时对最大值有影响。故我们可以对每一个询问,枚举合法的左端点,寻找最小右端点,复杂度至多为3131q,可以通过。
代码:略。。