week18 代码源oj每日一题div2

上帝的集合

在这里插入图片描述

思路:

这题比较简单,没有什么技巧,直接模拟即可。

#include<iostream>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
#define ll long long
int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int n;
	int op;
	ll x;
	vector<ll>a;
	
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>op;
		if(op==1||op==2)
		{
			cin>>x;
			if(op==1)
			{
				a.push_back(x);
			}
			else 
			{
				for(int j=0;j<a.size();j++)
				{
					a[j]+=x;
				} 
			}
				
		}
		else
		{
			vector<ll>::iterator it;
			it=min_element(a.begin(),a.end());
			cout<<*it<<'\n';
			a.erase(it);
		} 
	}
	
	return 0;
}

最长公共子序列

在这里插入图片描述

思路:

我们可以试图将原问题转化为更容易求解的问题。注意两行数都是各不重复的,则我们可以记录第一行每个数字对应的位置,再将第二行的数字进行对应转化,就将问题转化为了求最长上升子序列的长度,例如:
3 2 1 4 5
2 1 3 4 5
我们记录a[3]=1,a[2]=2,a[1]=3,a[4]=4,a[5]=5。
然后第二行数字相应的变为2 3 1 4 5
即把这两行数字变成了:
1 2 3 4 5
2 3 1 4 5
接下来就是求最长上升子序列的问题了。
注意,这题不能用简单的DP,O(n2)的复杂度过不了。我们可以选择用贪心+二分的方法。

#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	const int N=1e5+5;
	const int INF=0x3f3f3f3f;
	int n,len=0;
	int a[N],b[N];
	int f[N];

	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int x;
		cin>>x;
		a[x]=i; 
	}
	for(int i=1;i<=n;i++)
	{
		int x;
		cin>>x;
		b[i]=a[x];
		f[i]=INF;
	}
	//将问题转化为求最长上升子序列 
	f[0]=0;
	for(int i=1;i<=n;i++)
	{
		if(b[i]>f[len])
			f[++len]=b[i];
		else
		{
			int k=lower_bound(f+1,f+1+len,b[i])-f;	//f[k]是f中第一个大于或等于b[i]的元素 
			f[k]=b[i];
		}
	} 
	
	cout<<len;
	return 0;
}

漂亮数

在这里插入图片描述

思路:

这题比较巧妙。解析

#include<iostream>
#include<cstring>
using namespace std;

int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	const int N=200005;
	int n,k;
	bool flag=0;
	char a[N],b[N];
	cin>>n>>k>>a;
	for(int i=0;i<n;i++)
	{
		b[i]=a[i%k];
	}
	for(int i=0;i<n;i++)
	{
		if(a[i]<b[i])break;
		else if(a[i]>b[i])
		{
			flag=1;
			break;
		}
	}
	if(flag==1)		//进行高精度加一操作 
	{
		for(int i=k-1;i>=0;i--)
		{
			if(b[i]=='9')
			{
				b[i]='0';
			}
			else
			{
				b[i]++;
				break;
			}
		}
	}
	
	cout<<n<<'\n';
	for(int i=0;i<n;i++)
	{
		cout<<b[i%k];
	}

	return 0;
}

真假字符串

在这里插入图片描述

思路:

题目即求s1和s2的最长公共子序列长度是否为len-1。

#include<iostream>
using namespace std;
int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	string s1,s2;
	int len;
	int t=0,cnt=0;

	cin>>s1>>s2;
	if(s1==s2)
	{
		cout<<1;
		return 0;
	}
	len=s1.size();
	//题目即求s1和s2的最长公共子序列长度是否为len-1

	int p1=0,p2=0;
	bool flag=0;
	while(s1[p1]==s2[p2])
	{
		p1++;
		p2++;
		t++;
	}
	int p=p2,flag1=0;
	for(int i=p1+1;i<len&&p<len;i++)		//忽略s[p1]再判断 
	{
		if(s1[i]==s2[p])
		{
			p++;
			t++;
		}
		else 
		{
			if(flag1==1)
			{
				flag=1;
				break;
			}
			flag1=1;
			p++;
			i--;
		}
	}
	if(t!=len-1)
	{
		p=p1,flag1=0,flag=0;
		for(int i=p2+1;i<len&&p<len;i++)		//忽略s[p2]再判断 
		{
			if(s2[i]==s1[p])p++;
			else 
			{
				if(flag1==1)
				{
					flag=1;
					break;
				}
				flag1=1;
				p++;
				i--;
			}
		}
	}				

	if(flag==1)cout<<0;
	else cout<<1;


	return 0;
}

走不出的迷宫

在这里插入图片描述

思路:

这题比较简单,dfs、bfs、dp三种做法都可以,这里我给出dfs和bfs两种方法。

#include<iostream>
#include<queue>
using namespace std;
int n,m;
char map[105][105];
bool vis[105][105]={0};
int ans=1;
int next_x[2]={1,0};
int next_y[2]={0,1};
bool flag=0; 
/*void dfs(int x,int y)
{
	vis[x][y]=1;
	for(int i=0;i<2;i++)
	{
		int to_x=x+next_x[i];
		int to_y=y+next_y[i];
		if(to_x<=n&&to_y<=m&&vis[to_x][to_y]==0&&map[to_x][to_y]=='.')
		{
			ans=max(ans,to_x+to_y-1);
			dfs(to_x,to_y);
		}
	}
}*/
void bfs()
{
	queue<pair<int,int> >q;
	q.push(make_pair(1,1));
	vis[1][1]=1;
	while(!q.empty())
	{
		int x=q.front().first;
		int y=q.front().second;
		q.pop();
		for(int i=0;i<2;i++)
		{
			int to_x=next_x[i]+x;
			int to_y=next_y[i]+y;
			if(to_x<=n&&to_y<=m&&vis[to_x][to_y]==0&&map[to_x][to_y]=='.')
			{
				vis[to_x][to_y]=1;
				q.push(make_pair(to_x,to_y));
				ans=max(ans,to_x+to_y-1);
			}
		}
	}
	
}
int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m;
	
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			cin>>map[i][j];
//	dfs(1,1);
	bfs();
	
	cout<<ans;	
	return 0;
}

最长同余子数组

在这里插入图片描述

思路:

这题考查数论。记住,同余问题相减处理。这题即求最长的连续子序列,并且这一序列的差值数组中的所有元素的最大公因数大于等于2.

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long
int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	const int N=2e3+5;
	int n,cnt=1,ans=1;
	ll a[N];
	ll b[N];
	ll m=0;
	
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	for(int i=1;i<n;i++)
	{
		b[i]=abs(a[i+1]-a[i]);		
	}
	for(int L=1;L<n;L++)
	{
		ll k=b[L];
		for(int i=L+1;i<n;i++)
		{
			k=__gcd(k,b[i]);
			if(k>1)ans=max(ans,i-L+2);
		}
	}
	
	cout<<ans+1;
	return 0;
}

互质

在这里插入图片描述

思路:

这题是数论问题,我们注意满足条件的k一定不会是序列A中任意一个元素的因子的整数倍,所以我们除去1~m中是序列A中的所有元素的所有因子的整数倍后,剩下的数即为符合条件的k。

#include<iostream>
#include<cmath>
using namespace std;
const int N=1e5+5;
int n,m;
bool vis[N]={0};	//vis[i]==1表示k不能取i这个数
void solve(int x)	
{
	bool flag=0;
	for(int i=2;i<=sqrt(x);i++)//把x的所有因子的所有小于m的整数倍都标记 
	{
		if(x%i==0)
		{
			flag=1;
			if(vis[i]==0)
			{
				int j=i;
				while(j<=m)
				{
					vis[j]=1;
					j+=i;
				}
			}
			if(vis[x/i]==0)
			{
				int j=x/i;
				while(j<=m)
				{
					vis[j]=1;
					j+=x/i;
				}
			}
		}
	}
	if(flag==0)
	{
		int i=x;
		if(vis[i]==0)
		{
			while(i<=m)
			{
				vis[i]=1;
				i+=x;
			}
		}
			
	}
}
int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	
	int a[N];
	int b[N];
	int len=0;
	
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		if(a[i]!=1)solve(a[i]); 
	}
	b[len++]=1;
	for(int i=2;i<=m;i++)
	{
		if(vis[i]==0)b[len++]=i;
	}
	
	cout<<len<<'\n';
	for(int i=0;i<len;i++)cout<<b[i]<<'\n';
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值