A Three Friends
题意:三个人站在数轴上,每个人可以向左或者向右移动一次或者不移动,问怎样移动使得两两之间的距离和最短。
B Snow Walking Robot
题目很长,看到题目的第一眼就以为是难题,怕了。。。然后就没读题,去做的前面,当时没做出来,后来做的时候读题理解题意花了很长时间,弄清楚题意之后不难出思路
题意:以字符串的形式给出指令,U(向上),D(向下),L(向左),R(向右),使机器人按照指令运动,除了(0,0)作为起点和终点走两遍外,任何点只能走一遍,可以删除,重新组合指令,问最少删除多少指令后,可以使机器人满足条件走回原点。
思路:删除指令使L个数=R个数,U个数=D个数,就可以重新排列为正方形
C Yet Another Broken Keyboard
题意:给一串字符,再给出可以使用的字母,问用给的字母能够打出多少连续的子串,是连续的!
思路:用map,找到有多少个最长的只包含已知字母的子串,子串的个数为n*(n+1)/2,把所有的加起来
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <string>
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <stack>
#include <queue>
using namespace std;
#define mod 1e9+7
#define N 200001
#define inf 0x3f3f3f3f
const double PI = atan(1.0)*4.0;
typedef long long ll;
char a[200005];
int main()
{
map<char,int>m;
char c;
std::ios::sync_with_stdio(false);
// freopen("E:\\in.txt","r",stdin);
ll n;int k;
cin>>n>>k;
cin>>a+1;
a[n+1]=1;
for(int i=1;i<=k;i++)
{
cin>>c;
m[c]=1;
}
ll num=0,sum=0;
for(int i=1;i<=n+1;i++)
{
if(m[a[i]])
{
num++;
}
else
{
sum+=num*(num+1)/2;
num=0;
}
}
cout<<sum<<endl;
}
D Remove One Element
题意:删除一个数或者不删除所能得到的最长连续递增序列
代码
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <string>
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <stack>
#include <queue>
using namespace std;
#define mod 1e9+7
#define N 200001
#define inf 0x3f3f3f3f
const double PI = atan(1.0)*4.0;
typedef long long ll;
ll a[N],dp[N];
ll k=0,b[N];
int main()
{
std::ios::sync_with_stdio(false);
//freopen("E:\\in.txt","r",stdin);
int n;ll maxx=-1;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
a[0]=-1;
dp[0]=0;
for(int i=1;i<=n;i++)
{
if(a[i]>a[i-1])dp[i]=dp[i-1]+1;
else
{
dp[i]=1;
b[++k]=i-1;
}
}
b[++k]=n;
for(int i=1;i<=k;i++)
maxx=max(maxx,dp[b[i]]);
for(int i=1;i<k;i++)
{
if(dp[b[i]+2]==1)
{
if(a[b[i]+2]>a[b[i]])
maxx=max((dp[b[i]]+dp[b[i+2]]),maxx);
}
else
{
if(a[b[i]+2]>a[b[i]])
maxx=max(maxx,(dp[b[i]]+dp[b[i+1]]-1));
else
{
if(a[b[i]-1]<a[b[i]+1])
maxx=max(maxx,(dp[b[i]]+dp[b[i+1]]-1));
}
}
}
cout<<maxx<<endl;
}
E. Nearest Opposite Parity
题意:给一串数,每一个数都可以向左或者向右移动当前所在位置上的数,问最少移动多少次,使得奇数变为偶数,偶数变为奇数
这个题暂时还没搞懂。。。
F. Two Bracket Sequences
看懂了,但还不熟练还得多看几遍
题意: 输入两个括号序列 s,t(不一定合法),你需要构造一个尽可能短的合法括号序列使得s,t 都是这个序列的子序列(子序列意味着不用连续)
思路: dp[i][j][k]表示匹配到s的第i个字符,匹配到t的第j个字符,并且此时“(”的个数比“)”多k个的时候的最小合法序列长度,k的上限是200(s和t中最多200个“(”或者“)”)。
状态转移:
枚举答案合法序列的每一位放置“(”或者“)”
放置(,如果s[i]’(’ -> ni=i+1,t[j]’(’ -> nj=j+1, dp[ni][nj][z+1]=dp[i][j][z]+1
放置),如果s[i]’)’ -> ni=i+1,t[j]’)’ -> nj=j+1, dp[ni][nj][z-1]=dp[i][j][z]+1
整个过程需要满足0<=z<=200 下界是因为z<0时左括号个数小于右括号个数将无法形成合法序列。每一个步转移需要记录父节点坐标和父节点通过什么字符转移到当前状态,最终状态为dp[s.size()][t.size()][0],从这个状态沿着父节点回退到dp[0][0][0]。
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
const int maxn=210;
const int inf=0x3f3f3f3f;
int dp[maxn][maxn][maxn];
struct node{int x,y,z;char c;}st[maxn][maxn][maxn];
string s,t;
int sz,tz;
int nx,ny,nz;
inline void bfs(){
sz=s.size(),tz=t.size();
memset(dp,0x3f,sizeof dp);
dp[0][0][0]=0;
queue<node> q;q.push(node{0,0,0});
while(!q.empty()){
node tp=q.front();q.pop();
//'('
nx=tp.x+(tp.x<sz&&s[tp.x]=='(');
ny=tp.y+(tp.y<tz&&t[tp.y]=='(');
nz=tp.z+1;
if(nz<=200&&dp[nx][ny][nz]==inf){
dp[nx][ny][nz]=dp[tp.x][tp.y][tp.z]+1;
q.push(node{nx,ny,nz});
st[nx][ny][nz]=node{tp.x,tp.y,tp.z,'('};
}
//)
nx=tp.x+(tp.x<sz&&s[tp.x]==')');
ny=tp.y+(tp.y<tz&&t[tp.y]==')');
nz=tp.z-1;
if(nz>=0&&dp[nx][ny][nz]==inf){
dp[nx][ny][nz]=dp[tp.x][tp.y][tp.z]+1;
q.push(node{nx,ny,nz});
st[nx][ny][nz]=node{tp.x,tp.y,tp.z,')'};
}
}
}
int main(){
cin>>s>>t;
bfs();
string res="";
int x=sz,y=tz,z=0;
int px,py,pz;
while(x||y||z){
res+=st[x][y][z].c;
px=st[x][y][z].x;
py=st[x][y][z].y;
pz=st[x][y][z].z;
x=px,y=py,z=pz;
}
sz=res.size();
for(int i=sz-1;i>=0;--i)cout<<res[i];
cout<<endl;
return 0;
}