做题小结4

第一个

非常非常好的一道双指针二分神题 也是我自己想出来的

	for (int i = 1; i <= n; i++) {
//		 cnt=a[i].num;
//		while(tot+a[i].num>=0&&r<=n)
		while (sum[i] - sum[l - 1] + k < 0) {
			l++;
//			a[i].l=l;
		}
		a[i].l = l;
	}

这个是延申 采用往后的方式
之前money trees的延申是往前的 就是从后往前遍历
这个while 前缀和用的太好了

nodee check(int mid) {
	int len = n - mid + 1;
	nodee ans = {0, 0, 0};
	for (int i = 1; i <= len; i++) {
		if (sum[i + mid - 1] - sum[i - 1] + k >= 0) {
			if (a[i + mid - 1].l <= i) {
				ans.zhenjia = 1;
				ans.l = i;
				ans.r = i + mid - 1;
				return ans;
			}
		}
	}
	return  ans;
}

二分的代码 也是很好的
下面是money trees的

	int l=1;
	int r;
	for(int i=1;i<=n;i++)
	{
		if(h[i-1]%h[i]){
			l=i;
		}
		while(sum[i]-sum[l-1]>k)
		{
			l++;
		}
		ans=max(ans,i-l+1);
	}
	cout<<a
     for(int i=n-1;i>=1;i--)
	 {
		 if(h[i]%h[i+1]==0)
		 {
		  c[i]=c[i+1];
		 }
		 else {
			c[i]=i;
		 }
	 }

这个题 很好

第二个

这道题把我做惨了 我用的差分 但是写不出来 这个题 很明显的就是差分完了
数组求和后 你会发现 在遍历满足排列会发现根本不符合逻辑

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int range = 2e5 + 10;
int n;
int a[range];
string s;
int chafen[range];
void solve() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	cin >> s;
	s = ' ' + s;
//	map<int, int>ma;
	for (int i = 1; i <= n; i++) {
		if (s[i] == 'B') {
//			if (ma[a[i]] >= 1) {
					chafen[1]++;
					chafen[a[i]+1]--;
					
//			} else ma[a[i]]++;
		} else {
			if(a[i]>n)continue;
//			if (ma[a[i]] >= 1) {
				chafen[a[i]]++;
//			} 
//			else ma[a[i]]++;
		}
	}
	for (int i = 1; i <= n; i++) {
		chafen[i] += chafen[i - 1];
	}
	for (int i = 1; i <= n; i++) {
		cout << chafen[i] << " ";
	}
	/*
	B:1 5  
	R:2 2   (3 ,4,5)
	*/
	cout << endl;
	int cnt=0;
	for (int i = 1 ; i <= n; i++) {
//		if(ma[i])continue;
			if (i<=chafen[i]) {
				cout<<"ss"<<i<<endl;
				cnt++;
			     continue;
			}
			else 
			{
				cout<<i<<" "<<cnt<<endl;
				cout<<"NO"<<endl;return ;
			}	
	}
	cout << "YES" << endl;
	return ;
	return ;
}

signed main() {
	int t ;
	cin >> t;
	while (t--)
		solve();


}

这个判断的过程我试了好久也用了很多办法 上面那个是错的

但是我举个例子 如果4这chafen是有值的 但是你不好把握这个chafen前面有用了吗 如果有用你用个cnt记录下 那么问题来了chafen4是指能来到4的可能次数 前面的使用次数你怎么用一个代数式子表达和chafen4的关系 实在找不到关系 因为这个chafen数组不是前缀和 如果再求他的前缀和更是大错特错 那我来到1的可能方式一万种 求了前缀默认后面一起加起来一万次了
所以看了题解 知道是贪心和排列

每一个块都是有作用的 无论红蓝 所以是红你得保证你不能大的离谱 是蓝你不能小的离谱

第三个

我用的二分去写 我以为这个步数是单调的 于是我开始二分 不过二分中检查上限出了逻辑错误 做不出来了 同时我的起点也搞不出来

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int range = 2e5 + 10;
int n;
int m;
string s;
struct node {
	int one;
	int x, y;
};
node check(int mid) {
	int y = n - 1;
	int x = m - 1;
	int xx = 0;
	int yy = 0;
	node ans = {0, 0, 0};
	for (int i = 1; i <= mid; i++) {
		if (s[i] == 'L')	xx--;
		else if (s[i] == 'R')xx++;
		else if (s[i] == 'U')yy++;
		else yy--;
		if (abs(xx) > x || abs(yy) > y)return  ans;
	}
	vector<char>zy;
	vector<char>sx;
	map<char, int>ma;
	ma['R'] = 1;
	ma['L'] = 1;
	ma['U'] = 2;
	ma['D'] = 2;
    for(int i=1;i<=mid;i++)
	{
		if(ma[s[i]]==1)zy.push_back(s[i]);
		else sx.push_back(s[i]);
	}
	ans.one=1;
	if(sx.size()!=0)
	{
		char ch=sx[0];
		int  num1=0;
		for(auto i:sx)
		{
			if(i!=ch)break;else num1++;
		}if(ch=='U'){
			ans.x=1+num1;
		}
		else ans.x=n-num1;
	}
	else ans.x=1;
	if(zy.size()!=0)
	{
		char ch=zy[0];
		int  num2=0;
		for(auto i:zy)
		{
			if(i!=ch)break;else num2++;
		}
	//	cout<<ch<<" "<<num2<<endl;
		if(ch=='R'){
			ans.y=m-num2;
		}
		else ans.y=1+num2;
	}
	else ans.y=1;
	return ans;
}
void solve() {
	cin >> n >> m;
	cin >> s;
	if (n == 1 && m == 1) {
		cout << 1 << " " << 1 << endl;
		return;
	}
	int l = 1;
	int len = s.size();
	s = ' ' + s;
	int r = len;
	node lte = {0, 0, 0};
	while (l <= r) {
		int mid = l + r >> 1;
		node hs = check(mid);
		if (hs.one) {
			if (mid >= lte.one) {
				lte.one = mid;
				lte.x = hs.x;
				lte.y = hs.y;
			}
			l = mid + 1;
		} else r = mid - 1;
	}
	cout << lte.x << " " << lte.y << endl;
	return ;
}
signed main() {
	ios::sync_with_stdio();
	cin.tie(0);
	cout.tie(0);
	int t;
	cin>>t;
	while(t--)
	solve();
	return 0;
}
//	if (zy.size() && sx.size() && ma[s[i - 1]] != ma[s[i]] && i >= 2)
//			break;
//		else {
//			if (ma[s[i]] == 1)zy.push_back(s[i]);
//			else sx.push_back(s[i]);
//		}
//	ans.one = 1;
////	for(auto i:zy)cout<<i<<" ";
////	cout<<endl;
////	for(auto i:sx)cout<<i<<" ";
////	cout<<endl;
//	int w = 0;
//	for (auto i : sx) {
//		if (i == 'U')w++;
//		else w--;
//	}
//	if (w < 0)ans.x = n+w;
//	else ans.x = 1+w;
//	w = 0;
//	for (auto i : zy) {
//		if (i == 'R')w++;
//		else w--;
//	}
//	if (w < 0)ans.y = 1-w ;
//	else ans.y = m-w ;
//	return ans;

很愚蠢的代码 我以为上限就是n-1个 然后左右互相抵消 殊不知互相抵消是对的 我举个例子
LRRLLL 我假设我是3 你觉得这个可能吗
LRR可以存在 接着LLL肯定不行 但是我代码认为可以 因为最终只有2个L

第四个
拓扑排序 不多说了
第五个例题
这题其实我已经做的差不多了 就是不知道拓扑排序 导致没做出来 要是知道了 就可以写出来了 我当时知道深度 然后把他的父亲弄进去但是在这个图片

把dep=1减去 然后由于5--->4 我把4弄进新的vector了表示下一步的删除 这是不对的 4还有儿子呢 3-6 把6弄进去是对的
这是错点

#include<bits/stdc++.h>
#define int long long 
using namespace std;
const int range=5e5+10;
int n;
int k;int x,y;
int cnt[range];
vector<int>v[range];
int shenxia;
bool vis[range];
pair<int,int>p[range];
int  digui(vector<int>h,int k)
{
	if(k==0)return shenxia;
	vector<int>w;
//	for(auto j:h)
//	{
//		cout<<j<<" ";
//	}
//	cout<<endl;
	if(shenxia==2){if(k)return 0;}
	if(shenxia==3)
	{
		if(k>=2)return 0;
		else return 1;
	}
     for(auto i:h)
	 {
		 if(vis[i])continue;
		 for(auto j:v[i])
		 {
			 w.push_back(j);
		 }
			vis[i]=1;
		    shenxia--;
	 }
	return digui(w,k-1);
}
void init()
{
	for(int i=1;i<=n+50;i++)v[i].clear(),vis[i]=0,cnt[i]=0;
}
void solve(int t)
{
	
	cin>>n;
	cin>>k;
	for(int i=1;i<=n-1;i++)
	{
		cin>>x>>y;
		v[x].push_back(y);
		v[y].push_back(x);
		cnt[x]++;cnt[y]++;
		p[i].first=x;
		p[i].second=y;
	}
	if(t==311){
		cout<<n<<","<<k<<",";
		for(int i=1;i<=n-1;i++)
		{
			cout<<p[i].first<<p[i].second<<",";
		}
		cout<<endl;
	}
	/*
	1
	6 2
	2 5
	4 3
	6 2
	1 5
	4 5
	
	
	
	1
	6 2
	1 6
	4 6
	2 1
	3 1
	1 5
	*/
//		return ;
//	}
	if(n==1||n==2){
		cout<<0<<endl;
		init();
		return ;
	}
	vector<int>e;
	shenxia=n;
	for(int i=1;i<=n;i++)
	{
		if(cnt[i]==1){
			e.push_back(i);
		}
	}
   cout<< digui(e,k)<<endl;
	init();
	return ;
}
signed main()
{
	int t ;
	cin>>t;
	for(int i=1;i<=t;i++)
		solve(i);
}

忘了第几题
这个很简单 但是做题也启发到我一点 其实那个最终值其实和最小的ai比就行了 不用真的找出来这个值的 然后求gcd都是简单的了

困难版
这个是上面的困难版本
其实那个最终值其实和最小的ai比就行了
这句话很重要

然后做这个题的时候我当时写错了 举得例子太小了就写了个三层for循环 以为就可以选数彻底 殊不知 选的多了 这个彻底需要dfs 很明显dfs必炸 少说30的15次方你算算这个炸不炸 减枝也没用 ~~那个for循环代码在我的笔记本里 ~~

要sort的 因为理解为最小ai就是那个全相等数
下面给出正解思路 第一次for 1--n/2+1 没问题

我当时做题是一段一段计算的 比如说4有三段 6有5端
我枚举5/2段就相当一半的点都搞进去了 但是这么做 枚举选取肯定是要深搜的 for怎么可能彻底

然后下面一层就是i+1-n了 枚举所有的 这里可能会纳闷 我不是贪心的要一半点吗 我假设i=1 那么这一层我全要了呀 其实这没啥 因为我们最后只要枚举因子个数有n/2有就行了呀 我不在乎你选几个 况且对于i=1 枚举后面所有的 i=2枚举后面所有的 才不会漏解呀

然后这个答案必然出现在gcd里 我们只要找到最大的因子就行了
然后那些差为0采用合并的思想 别的没啥 不写了 好饿

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int range = 4e6 + 10;
int n;
int a[range];
int b[range];
int step;
int temp[range];
int maxn;
int maxnn;
void init()
{
	for(int i=1;i<=maxnn+10;i++)temp[i]=0;
}
void solve()
{
	int hs=0;
	cin>>n;
	map<int,int>ma;
	for(int i=1;i<=n;i++)cin>>a[i],ma[a[i]]++,hs=max(hs,ma[a[i]]);
	if(hs>=n/2){
		cout<<"-1"<<endl;
		return ;
	}
	sort(a+1,a+1+n);
//	for(int i=1;i<=n;i++)cout<<a[i]<<" ";
//	cout<<endl;
	int ans=0;
	//-15 13 16 22 35 48
	for(int i=1;i<=n/2+1;i++)
	{
		int res=0;
		 maxn=0;	
	//	cout<<"------"<<endl<<i<<endl;
		for(int j=i+1;j<=n;j++)
		{
			int x=a[j]-a[i];
	//		cout<<x<< " "; 
			maxn=max(x,maxn);			
			//找到最大因子 
			if(x==0)res++;
			for(int k=1;k*k<=x;k++)
			{
				if(x%k==0)
					temp[k]++;				
				if(k!=x/k&&x%(x/k)==0)			
					temp[x/k]++;
				//好煞笔 一开始写成else if 
				//然后还不写这个x%(x/k)==0 除非嵌套在上面那个if里
				//好煞笔
				
			}		
		}
	//	cout<<endl;	
	//	cout<<temp[13]<<endl;
		maxnn=maxn;
     	 
		while(temp[maxn]+res+1<n/2&&maxn>0){
			maxn--;
		}
	//	cout<<maxn<<endl;
	//	cout<<temp[maxn]+res+1<<endl;
	//	cout<<temp[13]<<endl;
		init();
		ans=max(ans,maxn);
	}
	cout<<ans<<endl;
	return ;
}
signed main() {
	ios::sync_with_stdio();
	cin.tie(0);
	cout.tie(0);
	int t;cin>>t;
	while(t--)
	solve();
	return 0;
}
/*
  1
  6
  48 13 22 -15 16 35
 */
//深搜时间过不去 太慢了 状态太多了 
//void solve() {
//	cin >> n;
//	init();
//	int cnt=0;
//	map<int, int>ma;
//	for (int i = 1; i <= n; i++) {
//		cin >> a[i];
//		ma[a[i]]++;
//		cnt=max(ma[a[i]],cnt);
//	}
//	sort(a+1,a+1+n);
//	if(cnt>=n/2){
//		cout<<"-1"<<endl;
//		return ;
//	}
//	step = 0;
////	for (int i = 1; i <= n - 1; i++) {
////		b[++step] = (a[i + 1] - a[i]);
////	}
////	sort(b+1,b+1+step);
////	for(int i=1;i<=step;i++)
////		cout<<b[i]<<" ";
////	cout<<endl;
//	int maxn = 0;
//	int mmaxn=0;
////	int xuanqu = step / 2;
//	int xuanqu = n / 2;
//	b[0]=0;
//	int zaixuan=xuanqu-1;
//	cout<<zaixuan<<" "<<xuanqu<<endl;
////	for (int i = 1; i <= n - xuanqu + 1; i++) {
////		for (int j = i+1 ; j <= n-zaixuan+1; j++) {
////			maxn=a[j]-a[i];
////			for (int k = 1; k <= zaixuan-1; k++) {
////				maxn = __gcd(maxn,a[j+k]-a[j+k-1]);
////			}
////			mmaxn=max(maxn,mmaxn);
////		}
////	} 
//	cout<<mmaxn<<endl;
//	return ;
//}
posted @ 2025-04-16 19:47  LteShuai  阅读(10)  评论(0)    收藏  举报