做题小结

好像身不由己 不能自己很失败
细细品味这一首歌 又记起来了hjk。

https://www.luogu.com.cn/problem/CF2024B

这个题也是逆天了 总结 我没做出来
然后我讲下我补题的思路吧 不知道和正解一样不一样
首先最基本的思路 就是我们先对所有的取一个min 这个就是一开始要拿的
再剔除最小值 然后一直重复这个操作 知道拿到k个为止
不过写起来我应该是写头晕了 昏招频出

#include<bits/stdc++.h>
#define int long long
#define debug cout<<endl<<"----------"<<endl;
const int range = 2e5+10;
using namespace std;
int n, k;
int a[range];
int s[range];
int lowbit(int x) {
	return x & -x;
}
void change(int x, int k) {
	while (x <= n)s[x] += k, x = x + lowbit(x);
}
int query(int x) {
	int t = 0;
	while (x)t += s[x], x = x - lowbit(x);
	return t;
}
int pre[range];
void solve(int t ) { //多测
	cin >> n >> k;
	map<int,int>ma;
	/*
	2 +4+2
	*/
	priority_queue<int, vector<int>, greater<int >> q;
	for(int i = 1; i <= n; i++) {
		cin >> a[i];
		ma[a[i]]++;
	}
	sort(a+1,a+1+n);
	int mini=a[1];
	if(n*mini>=k){
		cout<<k<<endl;return ;
	}	
	int ans=0;
	int cy=mini;
	k-=n*cy;
	ans=cy*n+1;
	for(int i=2;i<=n;i++)
	{
		int temp=a[i];
		a[i]-=cy;
		if(a[i]==0)ans++;
		else {			
			if((n-i+1)*a[i]>=k){			
					ans+=k;			
			
				cout<<ans<<endl;return ;
			}
			ans+=(n-i+1)*a[i]+1;
			cy=temp;
			k-=a[i]*(n-i+1);	
//			cout<<cy<<" "<<i<<endl;
		}
	}
	cout<<ans<<endl;
	
	
	
//	int sum = 0;
//	int ans = 0;
//	while (sum < k) {
//		int w = min(q.top(), k - sum);
//		int u = q.top();
//		q.pop();
//		u -= w;
//		sum+=w;
//		ans += w;
//		if(sum>=k)break;	
//		if (u == 0) {
//			ans++;
//		}
//	}
//	cout<<ans<<endl;
//	
	
	
	

for(int i=2;i<=n;i++)
	{
		int temp=a[i];
		a[i]-=cy;
		if(a[i]==0)ans++;
		else {			
			if((n-i+1)*a[i]>=k){			
					ans+=k;			
			
				cout<<ans<<endl;return ;
			}
			ans+=(n-i+1)*a[i]+1;
			cy=temp;
			k-=a[i]*(n-i+1);	
//			cout<<cy<<" "<<i<<endl;
		}
	}

如果ai取完一边不行 那么就继续 这没话说
如果可以的话 这边我真的很傻逼 比如5 5 5 8 9 我们要取5 一遍
我以为要+额外的5的数量-1 算作犯错机会 其实想多了 我们是很聪明的 手里记着多少呢
每个取5个就行 不用额外犯错

https://www.luogu.com.cn/problem/CF2027C

草 实在没想到 自己现在菜的离谱了 黄题都切不出来 以前切绿就跟切菜一样。。
退役老年选手 太卑微

当时思考到了做法这些 奈何思维退化 码力变弱

第一个做法 其实就是记忆化搜索 其实改改就是一个dfs图
这个挺好的一个思路

map<int, vector<int >> ma;
map<int, int>dp;
int dfs(int x)
{
	if(dp[x])return dp[x];
	int ans=x;
	dp[x]=ans;
	for(auto i:ma[x]){
		ans=max(ans,dfs(i+x));		
	}
    dp[x]=ans;
	return dp[x];	
}
void solve(int t ) { //多测
	cin >> n ;
	dp.clear();
	ma.clear();
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		if(i==1)continue;//防止死循环
		if(a[i]+i-1-n>=0)
		ma[a[i] + i - 1 - n].push_back(i - 1);
	}
  cout<<dfs(0)+n<<endl;

第二个是 朴素写法
用set记录重复出现的 如果出现了 就把贡献加上去
(我认为的朴素写法)

set<int>s;
pair<int, int>p[range];
bool cmp(pair<int, int>x, pair<int, int>y) {
	if (x.first == y.first)return x.second < y.second;
	return x.first < y.first;
}
void solve(int t ) { //多测
	cin >> n ;
	s.clear();
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		p[i].first = a[i] + i - 1;
		p[i].second = i - 1;
	}
	s.insert(n);
	sort(p + 1, p + 1 + n, cmp);
	for (int i = 1; i <= n; i++) {
		if (s.count(p[i].first)) {
			s.insert(p[i].first + p[i].second);
		}
	}
	cout << *s.rbegin() << endl;

通过这道题 也学到了东西

https://www.luogu.com.cn/problem/CF2032C

三角形 就是第二条边大于第三边 这道题一个二分 一个双指针写法
我投降 我没写出来 现在就是思路能想一些出来 慢慢的就会做出来了 还在恢复

第一个就是双指针了 无论怎么改变 数组中的值还是那几个 又不能凭空变出来
先sort排序
所以 我们可以想到一个On的写法 用for循环卡住某个i 表示什么呢

如果此时l与l+1是比你大的 意味着 选你做老大就好了 那么我们只需要改变
l之前的与你之后的 然后比较下答案就行

for(int r=2;r<=n;r++)
	{
		while(a[l]+a[l+1]<=a[r])l++;
		ans=min(ans,l-1+n-r);
	}

二分写法 经典Onlogn 用for循环卡住i
我当时就在想 一个最大值 一个最小值 我咋卡两个东西
人到无语是会笑的 太久没写题就是这样的 我以前做烂的模型。。
就是一个for循环卡住就行了 枚举最大值就行
二分一个mid表示最小 其实和双指针没什么区别

	int ans = 1e9;
	for (int i = n; i >= 2; i--) {
		int l = 1;
		int r = i - 1;
		//二分最小值
		int w = 0;
		while (l <= r) {
			int mid = l + r >> 1;
			if (a[mid] + a[mid + 1] > a[i]) {
				w = mid;
				r = mid - 1;
			} else l = mid + 1;
		}
		
//		cout<<i<<" "<<w<<endl;
		ans = min(ans, w - 1 + n - i);
	}
	cout<<ans<<endl;

https://www.luogu.com.cn/problem/CF2028B

这题大部分代码都想到了 就是一个 //我默认n=n-1的
然后我在判断 x=0时 错了 我认为都可以的 。。。
错在这里了 其实不是

if(x==0)
	{
		bool flag=0;
		if(y<=n)flag=1;
	 cout<<n+1-flag<<endl;    
		return ;
	}

仔细 写写就能发现了 如果你给n=8 n-1=7 给的y时6那我可以办到 如果n=9要8我就不行了
也是 没注意样例细节 想当然了
所以答案就出来了


		if(y+1>=n){
			/*
			6 7 
			*/
			if(y<=n)flag=1;
			cout<<n+1-flag<<endl; 
		return ;
		}

https://www.luogu.com.cn/problem/CF2028C

这题我做错了 我思考少了 我知道是双指针
这题先打住 需要回头补下二分写法 1.17

1.22补
这题其实题解双指针麻烦了 我们其实只要意识到一个点也是贪心思维 就是他是碰到可以切就切的 所以能切几份是固定的

for (int i = 1; i <= n; i++) {
		now += a[i];
		if (now >= v) {
			pre[i] = pre[i - 1] + 1;
			now = 0;
		} else pre[i] = pre[i - 1];
	}
	now = 0;
	for (int i = n; i >= 1; i--) {
		now += a[i];
		if (now >= v) {
			suf[i] = suf[i + 1] + 1;
			now = 0;
		} else suf[i] = suf[i + 1];
	}

只要求一个前后缀就行
只有统计答案才会纠结取不取
然后后续统计答案 我们只要枚举一个l r 即可

用双指针枚举l r会很方便 很基础的的写法

	for(int l=1;l<=n;l++)
	{
		while(r<n&&pre[l-1]+suf[r+2]>=m)r++;
		ans=max(ans,sum[r]-sum[l-1]);		
	}

用二分就有一点的难写 不过也是基本模型 卡一边

for (int i = 1; i <= n; i++) {
		int r = n;
		int l = i;
//		debug
//		cout << i << endl;
		while (l <= r) {
			int mid = l + r >> 1;
//			cout << mid << endl;
			if (check(i, mid)) {
//				cout<<l<<" "<<mid<<endl;
				ans = max(sum[mid] - sum[i - 1], ans);
				l = mid + 1;
//				break;
			} else r = mid - 1;
		}
	}

原题链接 方便看我的rz提交记录
https://codeforces.com/contest/2031/problem/B
https://www.luogu.com.cn/problem/CF2031B

逆天题目 wa了半天还是没做出来 看了题解 感觉自己是弱智
很明显的 对于一个数 如果他不在i+1 i i-1三个位置 永远变不回去 这是肯定的
然后就没了 果然人类精华

https://codeforces.com/contest/2031/problem/C

热知识 0和1都是完全平方数

这题考了1是完全平方数 明早写吧 刚补没多久

这题有点逆天 n是偶数 直接两个两个输出
n是奇数 就有点麻烦了 如果按照n是偶数的方法去写 一定会有一个多出来 那怎么解决呢 我是没想到的
不过这一个和勾股定理有关
n是奇数 -1 就是偶数
如果可以解决3的话 就可以解决奇数了 但是3是放不了的 5也是 一直到27才可以 我是看测试点才知道的
为什么呢 因为32+42=5^2这是一组最小的勾股定理

所以我们可以这样思考 一个放1 一个放10 一个放 26 刚好可以

于是就可以愉快的写了
不过还要注意一个就是由于10写了1那么 后续继续两个两个补就因为26又给隔开了
1 2 2 3 3 4 4 5 5 1 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 1 13
13和13 就隔开了 就不行 解决办法是第11个位置和27刚好是16所以可以单独搞下

这题个人认为是个绿 不好想的

posted @ 2025-01-17 00:08  LteShuai  阅读(24)  评论(0)    收藏  举报