iwtgm-13
A.
自己写的时候固定思维左右转换,上下转换,还分开求了最短子序列,从一开始就错了...
正解:
因为操作可以变成4个方向的任意一个,相当于有几个字符就可以有几个任意的操作
二分区间长度,for循环滑动窗口枚举子序列
计算部分用前缀和维护求出最终的x,y
计算x,y和终点的xx,yy还差多少步,若区间长度大于等于步数,且多出来的步数是偶数(来回抵消用)就满足条件
逐字符敲还是不对,所以就复制粘贴了
void solve() {
int n, sx, sy;
string s;
cin >> n >> s >> sx >> sy;
s = " " + s;
vector<int> u(n + 1), d(n + 1), r(n + 1), l(n + 1);
for(int i = 1; i < s.size(); i++) {
if(s[i] == 'U')u[i]++;
u[i] += u[i - 1];
if(s[i] == 'D')d[i]++;
d[i] += d[i - 1];
if(s[i] == 'R')r[i]++;
r[i] += r[i - 1];
if(s[i] == 'L')l[i]++;
l[i] += l[i - 1];
}
auto check = [&](int mid) {
for(int i = 1; i + mid - 1 <= n; i++) {
int U = u[i - 1] + u[n] - u[i + mid - 1];
int D = d[i - 1] + d[n] - d[i + mid - 1];
int R = r[i - 1] + r[n] - r[i + mid - 1];
int L = l[i - 1] + l[n] - l[i + mid - 1];
int x = R - L;
int y = U - D;
// debug2(x, y);
int res = abs(sx - x) + abs(sy - y);
// debug2(res, mid);
if(res <= mid && (mid - res) % 2 == 0)return true;
}
return false;
};
int li = 0, ri = n, ans = -1;
while(li <= ri) {
int mid = li + ri >> 1;
if(check(mid))ri = mid - 1, ans = mid;
else li = mid + 1;
}
cout << ans << endl;
}
B.
把除最后一行和最后一列以外的所有数都置为0
任何数异或0还等于这个数,这样一来既不影响答案,要考虑的也少了许多
然后最后一行除最后一个分别置为b[0],b[1]...
最后一列除最后一个数分别置为a[0],a[1],a[2]...
现在考虑最后一个数,它必须满足:(a[1]b[1]b[2]...b[m-1])=(b[m]a[2]a[3]...a[n])
事实上,它确实满足
异或有一个性质:若ax=b,那么a=bx
(a[1]a[2]a[3]...a[n])=(b[1]b[2]b[3]...b[m])
把a[1]代入到第一个式子,成立
int n,m,a[105],b[105];
int ans[105][105];
void solve(){
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=m;i++)cin>>b[i];
int cnt1=0,cnt2=0;
for(int i=1;i<=n;i++)cnt1^=a[i];
for(int i=1;i<=m;i++)cnt2^=b[i];
if(cnt1!=cnt2){
cout<<"NO";return ;
}
cout<<"YES"<<endl;
for(int i=1;i<n;i++){
for(int j=1;j<m;j++){
ans[i][j]=0;
}
}
for(int i=1;i<n;i++)ans[i][m]=a[i];
for(int i=1;i<m;i++)ans[n][i]=b[i];
for(int i=1;i<n;i++)b[m]^=a[i];
ans[n][m]=b[m];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cout<<ans[i][j]<<' ';
}
cout<<endl;
}
}
C.
两种状态
0,0,1,1,2,2递增这样的
0,0,1,1,3,3,1,1,3,3这样的,一旦不是以1递增,这里2没有出现,后面就只能1和3反复出现了
dp[n][0/1]表示第一种和第二种
这道题的dp跟正常的dp不太一样,有一点桶的性质
考虑的不是递推,是这个字符加进来,有哪些情况可以被改变和转移
然后第二种情况按照dp的意思是0,0,1,1,1,1,3,3,3,3
用正常的dp递推写这道题是非常复杂的,我还理解不了,用这种桶的方式计数较为方便
ll dp[N][2];
const int mod=998244353;
void solve()
{
int n;cin>>n;
for(int i=0;i<=n+1;i++){
dp[i][0]=0;dp[i][1]=0;
}
dp[0][0]=1;//初始化,因为0和1可以作为开头
for(int i=1;i<=n;i++){
int x;cin>>x;x++;//加1操作后会比较方便,因为1可以作为开头,但它后面就只能一直取1,因为比它小2的是负数,取不了,它相当于是第二种情况
dp[x][0]+=dp[x][0]+dp[x-1][0];//等号右边的第一项是当前字符已经存在的所有情况,是把x加在这些情况后面。第二项是当前字符直接加在x-1后面,相当于重复的第一个
dp[x][1]+=dp[x][1];//当前字符是第二种情况,可以加一倍
dp[x+2][1]+=dp[x+2][1];//就是在原来的所有情况上加上这个字符,写成[x+2]是桶的性质,可以这样等价,所以说是不大正常的dp
if(x>1)dp[x][1]+=dp[x-2][0];//把当前的字符当作第二种情况的开头,所以x-1是第一种情况的时候,也就是说,第二种情况的0,1,3,1 其实可以等价转化为:0,1,1,3,用桶计数
dp[x][0]%=mod;
dp[x][1]%=mod;
dp[x+2][1]%=mod;
}
ll ans=0;
for(int i=1;i<=n+1;i++){
ans+=dp[i][0]+dp[i][1];
ans%=mod;
}
cout<<ans<<endl;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现