首页 > 其他分享 >AT_abc344_D-String Bags 题解

AT_abc344_D-String Bags 题解

时间:2024-03-24 19:13:52浏览次数:30  
标签:Bags ch int 题解 cin ++ abc344 sl dp

明显是 DP。

然后就开始分析:

状态:\(dp_{ij} =\) 有 \(i\) 个袋子且匹配 \(T\) 的前缀的长度为 \(j\) 时所需的最少钱数。

匹配 \(T\) 的前缀的长度为 \(j\) 就是前 \(j\) 个字符与 \(T\) 的前 \(j\) 个字符相同。

相对简单。


然后看转移。为了方便,咱不妨令 \(|S|\) 为字符串 \(S\) 的长度,其它的同理。

假设是要将第 \(i\) 个袋子里的字符串 \(L\) 接到 \(S\) 的末尾,那么就只有 \(S_{|S|+1}\) 与 \(S_{|S|+|L|)}\) 依次对应时才能从 \(dp_{(i-1)|S|}\) 转移到 \(dp_{i|L|}\)。

为啥呢?

不对应那你接哪儿去了?不是说好接到末尾吗?那你问啥呢,浪费表情:-(

那我不选呢?

不选你 \(j\) 不变不就得了?

所以,转移部分就是:
for (int i = 0; i < n; i++) {
		for (int j = 0; j < 110; j++) dp[i + 1][j] = dp[i][j];  // 同步过去
		int m;
		cin >> m;
		while (m--) {
			...判断是否满足上面的条件
				if (满足) dp[i + 1][j + sl] = min(dp[i + 1][j + sl], dp[i][j] + 1);
			}
		}
	}

上面dp[i + 1][j + sl]就是不选,dp[i][j] + 1就是选。


最后看一下时间复杂度。

\(\Theta(NM|S|\cdot|T|)\)。\(M\) 为袋中字符串数量。

为啥?

你看我们上面的代码,不就是先遍历了一遍 \(N\) 个袋子,再遍历字符串数量 \(M\),每次判断相等挨个比较不就是 \(|S|\cdot|T|\)嘛。

结束~


ACCode
// Problem: D - String Bags
// Contest: AtCoder - 	Toyota Programming Contest 2024#3(AtCoder Beginner Contest 344)
// URL: https://atcoder.jp/contests/abc344/tasks/abc344_d
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
/*Code by Leo2011*/
#include <bits/stdc++.h>

#define log printf
#define EPS 1e-8
#define INF 0x3f3f3f3f
#define FOR(i, l, r) for (int(i) = (l); (i) <= (r); ++(i))
#define IOS                      \
	ios::sync_with_stdio(false); \
	cin.tie(nullptr);            \
	cout.tie(nullptr);

using namespace std;

typedef __int128 i128;
typedef long long ll;
typedef pair<int, int> PII;

const int N = 110;
int dp[N][N];  // dp[i][j] = 前 i 个袋子中匹配 T 的前缀长度为 j 时所需的最少钱数。
string t;

template <typename T>

inline T read() {
	T sum = 0, fl = 1;
	char ch = getchar();
	for (; !isdigit(ch); ch = getchar())
		if (ch == '-') fl = -1;
	for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - '0';
	return sum * fl;
}

template <typename T>

inline void write(T x) {
	if (x < 0) putchar('-'), write<T>(-x);
	static T sta[35];
	int top = 0;
	do { sta[top++] = x % 10, x /= 10; } while (x);
	while (top) putchar(sta[--top] + 48);
}

int main() {
	IOS memset(dp, INF, sizeof(dp));
	dp[0][0] = 0;
	cin >> t;
	int tl = t.size(), n;
	cin >> n;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < 110; j++) dp[i + 1][j] = dp[i][j];
		int m;
		cin >> m;
		while (m--) {
			string s;
			cin >> s;
			int sl = s.size();  // 比较
			for (int j = 0; j + sl <= tl; j++) {
				bool flag = true;
				for (int k = 0; k < sl; k++)
					if (t[j + k] != s[k]) {
						flag = false;
						break;
					}
				if (flag) dp[i + 1][j + sl] = min(dp[i + 1][j + sl], dp[i][j] + 1);  // 状态转移方程
			}
		}
	}
	if (dp[n][tl] > 5e8) dp[n][tl] = -1;  // 过大就是祭了
	cout << dp[n][tl] << "\n";
	return 0;
}

AC记录~

理解万岁!

标签:Bags,ch,int,题解,cin,++,abc344,sl,dp
From: https://www.cnblogs.com/leo2011/p/18092837

相关文章

  • P10111 [GESP202312 七级] 纸牌游戏 题解
    看标签知道要用DP。于是开始分析。状态:$dp(i,j,k)=$前\(i\)轮中,第\(i\)轮出\(j\),一共换了\(k\)次牌的最大钱数。很好理解。转移也不难,不就是不换和换两种吗!所以,转移就是:\[dp(i,j,k)=\max\begin{cases}dp(i-1,j,k)+\operatorname{pk}(j,c_i)\times......
  • [暴力题解系列]2023年蓝桥杯-整数删除(30分)
    这题暴力最多30分,但是30分也是分,做暴力的人不能贪心,拿到分就是赚了。​ 这题核心烦人点在于他数据分层断崖,就只有前3个点能做到稳过。用的思路就是链表,但不是用指针存的,而是用数组下标为标记存的,只是我觉得因为这样好写一些。链表方便修改左右连接位置,所以越到后面就越能省下查询......
  • 0318-0324题解
    成信大天梯赛L1-6二进制因为二进制是逢二进一,所以我们只要用cnt记录一下每一位上的数并给它加起来,然后cnt%2便是其和这一位上的数,注意要从右往左开始点击查看代码#include<bits/stdc++.h>usingnamespacestd;typedefpair<int,int>pii;voidsolve(){stringa,b......
  • 广州大学第十八届ACM大学生程序设计竞赛(同步赛)——题解
    这套题我答的很失败。没有按照题目的难度去答题,前期浪费了不少时间。题目:A-字符画题解:思维、模拟。这道题我的通过率为62.5,没有过的原因是因为对细节的处理和把控不到位,对一些点忽视,我也记录了搜索的过程,但没有把搜索过的点消掉,而且没有找到最好的顺序去解答这道题,我是按照横的......
  • 字母迷宫题解
    思路:看到这题一眼跑广搜,但是转眼天堂之门,欸为什么要加2?好像没法广搜(不满足广搜特性),咋办?凉拌。该怎么让它满足广搜特性(先搜到的是最优的)。欸,我们是不是可以将队列换成优先队列让先搜到的最优。好像是的欸,优先队列启动!代码:#include<bits/stdc++.h>usingnamespacestd;inta......
  • cfEduRound163div2--D题解
    D-TandemRepeats?题意:做法:因为字符串长度较少,可以考虑枚举。or--动态规划voidsolve(){//D枚举//枚举!!!!!!!!!!stringstr;cin>>str;intn=str.size(),ans=0;for(inti=1;i<=n/2;i++){//枚举一半!!!intcnt=0;for(intj=0;......
  • 题解 CF1948G【MST with Matching】
    非常精彩的转化!显然,树是二分图。由König定理,我们知道:二分图最小点覆盖等于最大匹配。因此枚举点覆盖\(S\),则一条边\((u,v)\)可以被选择,当且仅当\(u\inS\lorv\inS\),在所有可以选择的边上跑最小生成树即可。我采用的是Kruskal算法,时间复杂度为\(O(2^nn^2\logn)\),可......
  • 20240324每日一题题解
    20240324每日一题题解Problem给两个按照非递减顺序排列的整数数组num1和num2,另外有两个整数m和n,分别表示num1和num2中的元素数目。请合并num2到num1中,使得合并后的数组还是按照非递减顺序排列。注意,需要将合并之后的数组还是存储在数组num1中。示例1:输入:nums1=[1,2,3,0,......
  • 牛客周赛ROUND37--C题解
    C-红魔馆的馆主(495倍数)题意:做法:dfs搜索后面添加的数字。stringans="1000000000000000000";voiddfs(intcur,stringaddnum){//用数字写的话会无限dfs,因为addnum永远等于0。if(cur==0){if(addnum.size()<ans.size())ans=addnum;return;......
  • 最长子字符串的长度(二)【华为OD机试JAVA&Python&C++&JS题解】
    一.题目-最长子字符串的长度(二)给你一个字符串s,字符串s首尾相连成一个环形,请你在环中找出’l’、‘o’、‘x’字符都恰好出现了偶数次最长子字符串的长度。输入描述:输入是一串小写的字母组成的字符串。输出描述:输出是一个整数补充说明:1<=s.length<=5x10^5......