当前位置: 首页 > news >正文

公式推导+dfs简版

写在前面的话:心可以冷,但手不能停
第一题:C. Flexible String
题目大意:给一个aaa字符串和bbb字符串和数字kkk,首先设置一个计数器cntcntcnt,其中可以对aaa字符串做以下操作:替换aaa中的一个字母xxx,将字母xxx加入到集合QQQ,如果这个字母已经在集合QQQ中了,则cntcntcnt不动,否则cnt++cnt++cnt++,记s[l,r]s[l,r]s[l,r]为在[l,r][l,r][l,r]区间中aaabbb的字母全相等。达到的目标为在cnt≤kcnt \leq kcntk的情况下,让s[l,r]s[l,r]s[l,r]的数量最大。
解题思路: 这个题可以这样想,对于任意一个a[i]≠b[i]a[i] \neq b[i]a[i]=b[i],可以将这个位置记作一个断点,被断点隔开的若干个区间可以用这样的形式来表达s[l,r]s[l,r]s[l,r]的数量:len∗(len+1)/2len*(len+1)/2len(len+1)/2,其中len为区间内的字母数量。我们注意到如果将某个满足a[i]≠b[i]a[i] \neq b[i]a[i]=b[i]的字母加入到集合QQQ中,则区间可能被连上,注意可能断点是由两个字母组成的。这样的话,考虑k最大可能为101010,则可以用数位dpdpdp或者dfsdfsdfs等,来枚举所有可能性。枚举出一种可能性,之后只要用O(n)O(n)O(n)判断即可,大概是10810^8108这样的级别,那么这里的枚举状态可以用这种形式表达:

for(int i=0;i<1024;i++)

注意,由于我把集合中的字母用mapmapmap映射,所以所有字母不能映射到000,否则wronganswerontest3wrong\space answer \space on\space test3wrong answer on test3
代码

#include<iostream>
#include<cstdio>
#include<vector>
#include<stack>
#include<map>
using namespace std;
typedef long long ll;
const int length = 1e5 + 5;
char a[length];
char b[length];
ll max(ll a, ll b)
{if (a > b)return a;else return b;
}
ll solve(int i, map<char, int> &mp,int n,int k)
{vector<int> flag(20, 0);int q = 0;for (int j = 1; j <= 10; j++){if (i&(1 << j)){flag[j] = 1;q++;}}if(q>k)return 0;int s = 0;ll res = 0;while (s < n){int tmp = s;while (a[s] == b[s]||flag[mp[a[s]]]==1){s++;if (s >= n)break;}int len = s - tmp;res = res + (ll)(len + 1)*len / 2;s++;}return res;}
int main(void)
{int t;scanf_s("%d", &t);for (int i = 0; i < t; i++){int n;int k;scanf_s("%d%d", &n, &k);getchar();//收\nscanf_s("%s", a,sizeof(a));getchar();//收\nscanf_s("%s", b,sizeof(b));getchar();map<char,int> mp;int cnt = 0;for (int i = 0; i < n; i++){if (a[i] != b[i]){if (mp[a[i]] == 0){mp[a[i]] = ++cnt;}}}if (cnt <= k){ll tmp = (ll)n*(n + 1) / 2;printf("%lld\n", tmp);continue;}vector<ll> dp(1500, 0);ll ans = -1;for (int i = 0; i < 1024; i++){ll a=solve(i*2, mp,n,k);ans = max(ans, a);}printf("%lld\n", ans);}
}

第2题:D. Flexible String Revisit
这个题比较有意思
题目大意: 给一个由0和1组成的两个字符串,对字符串a可以做以下操作:可以任选一个数字对其进行反转,问达到两个字符串第一次相等所需要的操作次数期望。
解题思路
参考文章
代码:

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
typedef long long ll;
int mod = 998244353;
const int length = 1e6 + 5;
int f[length][2];
int dp[length];
char a[length];
char b[length];
int ksm(int k)
{int tmp = mod-2;int base = k;int ans = 1;while (tmp){if (tmp % 2 == 1){ans = (ll)ans*base%mod;}base = (ll)base*base%mod;tmp = tmp >> 1;}return ans;
}
int solve(int n, int k)
{f[n][0] = 1;f[n][1] = 1;for (int i = n-1; i >= 0; i--){int now = ((ll)1 - (ll)(n - i)*f[i + 1][1]%mod *ksm(n) % mod + mod) % mod;f[i][0] = ((ll)1 + (ll)(f[i+1][0])*(n-i)%mod*ksm(n) % mod) % mod*ksm(now)%mod;f[i][1] = (ll)i*ksm(n) % mod*ksm(now) % mod;}dp[0] = f[0][0];for (int i = 1; i <= k; i++){dp[i] = (ll)((ll)dp[i - 1] * f[i][1] % mod + f[i][0]) % mod;}return dp[k];
}
int main(void)
{int t;scanf_s("%d", &t);for (int i = 0; i < t; i++){int n;scanf_s("%d", &n);int k = 0;getchar();scanf_s("%s", a,sizeof(a));//a.push_back(t);getchar();scanf_s("%s", b, sizeof(b));getchar();for (int i = 0; i < n; i++){if (a[i] != b[i])k++;}int a1=solve(n, k);printf("%d\n", a1);}
}
http://www.lryc.cn/news/37993.html

相关文章:

  • 论文笔记 | 标准误聚类问题
  • 银行管理系统--课后程序(Python程序开发案例教程-黑马程序员编著-第7章-课后作业)
  • 【18】组合逻辑 - VL18 实现3-8译码器①
  • 2020蓝桥杯真题最长递增 C语言/C++
  • 华为OD机试题 - 寻找连续区间(JavaScript)| 机考必刷
  • 一次疲惫的调试--累了及时透气
  • 综合练习7 摄氏度转华氏温度(“\t“的使用,循环语句)
  • AWS数据库总结
  • 2个步骤就能批量给视频添加滚动字幕
  • PHP 的运行方式有哪些?
  • Web学习3_JavaScript
  • 「MySQL基础」不可重复读和幻读的区别
  • CorelDRAW2023最新版新增功能200多个新模板
  • springboot自定义日志以及行号正确展示
  • 【GAOPS055】verilog 乘法、除法和取余
  • TCP UPD详解
  • 金三银四、金九银十 面试宝典 MySQL面试题 超级无敌全的面试题汇总(超万字的面试题,让你的MySQL无可挑剔)
  • 【Java】初识Java
  • JVM相关知识
  • 【LeetCode】剑指 Offer(21)
  • 线性求解器Ax=b的验证
  • java 事件处理机制 观察者模式
  • 使用 HTML5 轻松验证表单插件
  • 【Error: ImagePullBackOff】Kubernetes中Nginx服务启动失败排查流程
  • 九龙证券|直逼1.5万亿!A股融资余额创年内新高,青睐这些行业和个股
  • 【JavaScript】36_正则表达式
  • 参考 | 辨别真假笔记本三星内存条 (ddr4)
  • JavaScript Math(算数)对象
  • MyBatis里面用了多少种设计模式?
  • 第三十二周精华分享(2023.02.27-2023.03.06)