iwtgm-20
题目链接
dp
确实没想到这种递推方式,一直绕在把整个网格分成k块,又要满足颜色不同,实在解不出来
dp的设置状态不是没想过,像这样的设置的确超出我的水平了
现在详细讲讲
只有两行,若两行的颜色块状态已知,我们是可以判断什么情况联通块会+1,什么情况是不变的,我们进行枚举即可
f[i][j][type]表示第i列,已经有j个联通块,type是上下颜色块的状态
这里我们设置0为BW,1为BB,2为WW,3为WB
来个例子:
第一列是B 第二列是B 那么我们的联通块数是不变的
W。 W 因为B与前一列的B属于同一个联通块,W同理
第一列是B 第二列是W 那么我们的联通块数+2
W。 B。 因为W不能属于前面任何一个联通块,联通块数+1,B同理
得到状态转移方程:
f[i][j][0]=f[i-1][j][0]+f[i-1][j-1][1]+f[i-1][j-1][2]+f[i-1][j-2][3];
f[i][j][1]=f[i-1][j][0]+f[i-1][j][1]+f[i-1][j-1][2]+f[i-1][j][3];
f[i][j][2]=f[i-1][j][0]+f[i-1][j-1][1]+f[i-1][j][2]+f[i-1][j][3];
f[i][j][3]=f[i-1][j-2][0]+f[i-1][j-1][1]+f[i-1][j-1][2]+f[i-1][j][3];
注意初始化第一列,第一列4种摆放方式都有可能
int n,k;
int dp[1010][2010][5];
const int mod=998244353;
void solve() {
cin>>n>>k;
dp[1][1][1]=1;dp[1][1][2]=1;dp[1][2][0]=1;dp[1][2][3]=1;
for(int i=2;i<=n;i++){
for(int j=1;j<=k;j++){
dp[i][j][0]=(dp[i][j][0]+dp[i-1][j][0])%mod;dp[i][j][0]=(dp[i][j][0]+dp[i-1][j-1][1])%mod;dp[i][j][0]=(dp[i][j][0]+dp[i-1][j-1][2])%mod;if(j>=2)dp[i][j][0]=(dp[i][j][0]+dp[i-1][j-2][3])%mod;
dp[i][j][1]=(dp[i][j][1]+dp[i-1][j][0])%mod;dp[i][j][1]=(dp[i][j][1]+dp[i-1][j][1])%mod;dp[i][j][1]=(dp[i][j][1]+dp[i-1][j-1][2])%mod;dp[i][j][1]=(dp[i][j][1]+dp[i-1][j][3])%mod;
dp[i][j][2]=(dp[i][j][2]+dp[i-1][j][0])%mod;dp[i][j][2]=(dp[i][j][2]+dp[i-1][j-1][1])%mod;dp[i][j][2]=(dp[i][j][2]+dp[i-1][j][2])%mod;dp[i][j][2]=(dp[i][j][2]+dp[i-1][j][3])%mod;
if(j>=2)dp[i][j][3]=(dp[i][j][3]+dp[i-1][j-2][0])%mod;dp[i][j][3]=(dp[i][j][3]+dp[i-1][j-1][1])%mod;dp[i][j][3]=(dp[i][j][3]+dp[i-1][j-1][2])%mod;dp[i][j][3]=(dp[i][j][3]+dp[i-1][j][3])%mod;
}
}
ll ans=0;
ans=(ans+dp[n][k][0])%mod;
ans=(ans+dp[n][k][1])%mod;
ans=(ans+dp[n][k][2])%mod;
ans=(ans+dp[n][k][3])%mod;
cout<<ans;
}
B.
又是一道从一开始就想错的题
因为后来才发现比如先往右上再往右下等价于往右移动两格,也就是用对角的方式走了水平或垂直的路,然后就去想把水平或竖直的路径变成对角的,认为直接走真正对角的不会最优
没想到就是先走真正的对角,然后再考虑把水平或竖直变成对角更为好做,服了
这个图中,我们可以把对角换成一个水平和一个竖直,也可以把一个水平和一个竖直换成一个对角
从原点到目的地需要的最小步数是max(a,b) (连这个都忘了我服了)
若k<max(a,b),那么就输出-1
考虑合法情况的最优解:
先走真正的对角到达b限定的高度
a和b表示终点坐标,设a为较大数
如果(a-b)%2==0,那么我们把用对角的方式走水平线(方式为必须两个水平线换两个对角)
第一次走到终点后,若剩余步数是偶数,那么用对角的方式从终点来回跳
若剩余步数是奇数,要求最后要走到目的地,那么就把前面的一个对角换成一条水平线和一条竖直线,此时对角的贡献-1,可以到达目的地
如果(a-b)%2==1,
那么必须要消耗一个步数走平路以到达目的地
第一次走到终点后,若剩余步数是偶数,那么以对角的方式在终点来回跳
若是奇数,把平路的那条改成对角,再花费一个步数从对角走到终点,对角+1
代码:
void solve() {
ll n,m,k;cin>>n>>m>>k;
if(n>m)swap(n,m);//n为较小数
ll res=max(n,m);//从原点到终点所需最小步数
if(res>k){//步数不够
cout<<-1<<endl;return ;
}
ll ans=n;//先把真正的对角走完,此时到达b限定的高度
ll x=k-res;//剩余的步数
ll y=abs(n-m);//多出来的那段路
if(y&1)ans+=y-1;//花费1个步数走平路,其余都走对角(是偶数)
else ans+=y;//是偶数,全走对角
if(x&1)ans+=x-1;//先把偶数个来回跳,剩下一个后面处理
else ans+=x;//偶数直接来回跳完
if(x&1&&y&1)ans++;//把平路花费的那一条变成对角,多出来的这一步从对角走到终点
else if(y%2==0&&x&1)ans--;//把原来的一个对角改成平路,再加上剩余的1个也走平路,等价于原来的那个对角
cout<<ans<<endl;
}
C.
选择每个序列的最后一个值,一定是最大的,如果这个组合没有被禁止,那么就输出
如果禁止了
答案的形式一定是某一个被禁止的组合调整一个取值所得到的组合,调整指将一个取值替换为前一个数
因为最大的组合被禁止了,我们此时应该去找这个组合调整一个取值所得到的组合,如果没有被禁止,就输出,如果又都被禁止了,那就只能从这些被禁止的组合里再去调整取值,然后因为我们是取最大值,所以多找是没有影响的
又知一个组合被调整一次一定优于调整两次的,也许你会说调整的那两个比那一个小,那么我会说那我直接调整那一个比较小的不就行了,一个小一定比两个小小
证毕
用到哈希,题解的代码写得还是非常优美,值得学习
const int b1=1e5+1,b2=3e5+3,m1=20060527,m2=21071179;
int n,m,cnt=1,num;
int tmp[11],a[11][N],c[N],ban[N>>1][11];
map<pair<int,int>,bool>mp;
struct build{
int ans,p[11];
pair<int,int>hsh;
}b[N*5];
void inw(){
int sum=0,h1=0,h2=0;
num++;
for(int i=1;i<=n;i++){
sum+=a[i][tmp[i]];
b[num].p[i]=tmp[i];
h1=(h1*b1%m1+tmp[i])%m1;
h2=(h2*b2%m2+tmp[i])%m2;
}
b[num].ans=sum;
b[num].hsh= make_pair(h1,h2);
}
bool cmp(build x,build y){
return x.ans>y.ans;
}
void solve() {
cin>>n;
for(int i=1;i<=n;i++){
cin>>tmp[i];c[i]=tmp[i];
for(int j=1;j<=c[i];j++){
cin>>a[i][j];
}
}
inw();
cin>>m;
for(int i=1;i<=m;i++){
int h1=0,h2=0;
for(int j=1;j<=n;j++){
cin>>ban[i][j];
tmp[j]=ban[i][j];
h1=(h1*b1%m1+tmp[j])%m1;
h2=(h2*b2%m2+tmp[j])%m2;
}
mp[make_pair(h1,h2)]=1;
}
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++)tmp[j]=ban[i][j];
for(int j=1;j<=n;j++){
if(ban[i][j]==1)continue;
tmp[j]--;
inw();
tmp[j]++;
}
}
sort(b+1,b+1+num,cmp);
for(int i=1;i<=num;i++){
if(!mp[b[i].hsh]){
for(int j=1;j<=n;j++){
cout<<b[i].p[j]<<' ';
}
return ;
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现