1.14 构造

1504B - Flip the Bits (1200)

题意

给出a, b两个01字符串,你可以对a进行操作:选定一个下标i,然后将i以及i之前的所有元素由1变成0,由0变成1,且从开头到下标i的元素中0和1的数量必须相等。问是否可以进行若干次操作使a变成b

思路

题目给出的操作要求很重要,第一个是前缀,第二个是01数量相等。那么我们可以考虑,枚举字符串a,设定ct1记录a中1的数量,ct0记录a中0的数量,每当ct1等于ct0时判断这i个元素是否是全不相同或是全都相同,否则判NO。
最后a中01数量可能不相等,所以从最后一个01相等的下标+1开始,一直到结尾,如果ab元素不相等,判NO。否则YES

void solve() {
	int n;
	cin >> n;
	string a, b;
	cin >> a >> b;
	
	int ct1 = 0, ct0 = 0;
	int l = 0, r = n - 1;
	for (int i = 0; i < n; i ++) {
		if (a[i] == '1') ct1 ++;
		else ct0 ++;
		
		if (ct1 == ct0 && ct1 != 0) {
			r = i;
			int x = 0, y = 0;
			for (int j = l; j <= r; j ++) {
				if (a[j] == b[j]) x ++;
				else y ++;
			}
			
			if (!(x == (r - l + 1) || y == (r - l + 1))) {
				cout << "NO" << endl;
				return ;
			}
			
			l = r + 1;
		}
	}
	
	if (l != n) {
		for (int i = l; i < n; i ++) {
			if (a[i] != b[i]) {
				cout << "NO" << endl;
				return ;
			}
		}
	}
	
	cout << "YES" << endl;
}

\[\]

1497B - M-arrays (1200)\(\delta\)

题意

给出含有n个元素的序列a,和m。你需要将a分成几个集合,每个集合中相邻元素相加需要被m整除。问最少可以分为几个集合

思路

正常模拟即可。不过要想到用map和将元素模m化简。
如果模后为0,则表示为m的倍数,可以全部放到一个集合中,如m = 4, 4 8 16 都可以放在一个集合中
如果该元素的两倍是m,则也可以全部放到一个集合中,如m = 4, 2 2 2 放在一个集合中
否则我们对于a中可以配对的元素或者单独的元素进行判断
如m = 4,可以是
1 3 1 3 1
1 3 1 3
两种
所以两种元素若要放进一个集合他们的差值最多不超过一个,否则只能单独存放

void solve() {
	int n, m;
	cin >> n >> m;
	vector<int> a(n + 1);
	for (int i = 1; i <= n; i ++) {
		cin >> a[i];
	}
	
	map<int, int> mp;
	
	int ans = 0;
	
	for (int i = 1; i <= n; i ++) {
		mp[a[i] % m] ++;
	}
	
	for (auto i : mp) {
		if (i.first == 0) {
			ans ++;
		}else if (i.first * 2 == m) {
			ans ++;
		}else if (i.first * 2 < m || mp[m - i.first] == 0) {
			int x = i.second, y = mp[m - i.first];
			ans += 1 + max(0, abs(x - y) - 1);
		}
	}
	
	cout << ans << endl;
}

\[\]

1446A - Knapsack (1300)

题意

给出含有n个正整数的序列a,还有一个总价值W,问是否能在数组中找到几个数的和sum满足 (w + 1) / 2 <= sum <= w

思路

因为求的是个范围,所有可以用双指针来模糊表示。这种问题若是条件变为查找和为W,则是子集和问题,n很大的话没看到好的解法,一般解法有枚举,dfs回溯

typedef long long LL;
typedef pair<int, int> PII;
void solve() {
	int n;
	LL w;
	cin >> n >> w;
	vector<PII> a(n + 1);
	for (int i = 1; i <= n; i ++) {
		int x;
		cin >> x;
		a[i] = {x, i};
	}
	
	sort(a.begin() + 1, a.end());
	
	int l = 1, r = -1;
	LL sum = 0;
	
	for (int i = 1; i <= n; i ++) {
		sum += a[i].first;
		if (sum >= (w + 1) / 2 && sum <= w){
			r = i;
			break;
		} else if (sum > w) {
			while (sum > w) {
				sum -= a[l].first;
				l ++;
			}
			
			if (sum >= (w + 1) / 2 && sum <= w){
				r = i;
				break;
			}else {
				r = -1;
				break;
			}
		}
	}
	
	if (l > r || sum < (w + 1) / 2 || sum > w) cout << -1 << endl;
	else {
		cout << r - l + 1 << endl;
		for (int i = l; i <= r; i ++) {
			cout << a[i].second << " \n"[i == r];
		}
	}
}

\[\]

1425H - Huge Boxes of Animal Toys (1300)

题意

给出四个盒子,盒子里有不同数量的玩具,每个玩具都有快乐值
以下是四个盒子能装的快乐值的范围

现在要将所有玩具的快乐值乘在一起,问最后可能会被装在哪个盒子里

思路

纯纯分类讨论

void solve() {
	int a, b, c, d;
	cin >> a >> b >> c >> d;
	string s = "Ya", t = "Tidak";
	if ((a + b) % 2 == 0) {             //正数 3, 4
		cout << t << ' ' << t << ' ';
		if (b != 0 || c != 0) {
			cout << s << ' ';
		} else cout << t << ' ';
		
		if (a != 0 || d != 0) {
			cout << s << endl;
		}else cout << t << endl;
	}else {                            //负数 1, 2
		if (a != 0 || d != 0) {
			cout << s << ' ';
		} else cout << t << ' ';
		
		if (b != 0 || c != 0) {
			cout << s << ' ';
		}else cout << t << ' ';
		
		cout << t << ' ' << t << endl;
	}
}

\[\]

1408B - Arrays Sum (1400)

题意

给出含有n个元素的序列a,m个含有n个元素的数组b和每个b数组最大拥有的元素种类数量k。现在告知我们a是由b数组每列共m个元素加和起来的,问m最少为多少可以满足要求

思路

因为a数组给的是有序的,所以很容易可以想到,贪心的直接每个b数组都取k种元素,加和起来即可。但要注意,除了第一个b数组外,后面的数组因为前面必须是0,才能保证前面数组元素的有效,所以后面的数组只能取k - 1种元素。直接计算即可

void solve() {
	int n, k;
	cin >> n >> k;
	vector<int> a(n + 1);
	for (int i = 1; i <= n; i ++) {
		cin >> a[i];
	}
	set<int> se;
	int ans = 0;
	for (int i = 1; i <= n; i ++) {
		se.insert(a[i]);
	}
	
	int tmp = se.size();
	if (tmp > 1 && k == 1) {
		cout << -1 << endl;
		return ;
	} 
	
	if (tmp > k)
		tmp -= k;
	else {
		cout << 1 << endl;
		return ;
	}
	ans += 1;
	k --;
	ans += tmp / k;
	if (tmp % k != 0) ans ++;
	
	cout << ans << endl;
}

\[\]

1393B - Applejack and Storages (1400)

题意

给出含有n个元素的序列a,里面的元素代表棍子的长度。有q次询问,每次会增加或者减少某种棍子的数量。你需要回答增加或减少棍子之后是否能拼成一个长方形和一个正方形。

思路

遇到这种肯定需要用到map当桶存棍子数量和记录变化,同时怎么判断现在有多少个四个一样长度棍子,和有多少个两个一样长度的棍子,所以cnt2表示仓库里两个一样长的棍子的数量,cnt4表示有四个一样长的数量。
若cnt2 >= 4 && cnt4 >= 1,(意为四根一样长的棍子组数至少有1组,两根一样长的棍子组数至少有4组,因为正方形需要四根一组,两根两组,长方形需要两根两组)则说明一定可以满足要求

void solve() {
	int n;
	cin >> n;
	map<int, int> mp;
	int cnt2 = 0, cnt4 = 0;
	for (int i = 1; i <= n; i ++) {
		int x;
		cin >>x;
		mp[x] ++;
	}
	
	for (auto i : mp) {
		cnt2 += i.second / 2;
		cnt4 += i.second / 4;
	}
	
	int q;
	cin >> q;
	while (q --) {
		char c;
		int x;
		cin >> c >> x;
		if (c == '-') {
			cnt2 -= mp[x] / 2;
			cnt4 -= mp[x] / 4;
			mp[x] --;
			cnt2 += mp[x] / 2;
			cnt4 += mp[x] / 4;
		}else {
			cnt2 -= mp[x] / 2;
			cnt4 -= mp[x] / 4;
			mp[x] ++;
			cnt2 += mp[x] / 2;
			cnt4 += mp[x] / 4;
		}
		
		if (cnt4 >= 1 && cnt2 >= 4) {
			cout << "YES" << endl;
		}else cout << "NO" <<endl;
	}
}

总结:基本思路有,但是实现很成问题,慢慢在提升

posted @ 2023-01-14 20:30  nobodyL  阅读(25)  评论(0)    收藏  举报