上帝的集合
思路:
这题比较简单,没有什么技巧,直接模拟即可。
#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;
}