A题
贪心就能过。没有坑点。
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
int n, m, r;
int main()
{
n = read();
m = read();
r = read();
int maxx=1e9;
int x;
int ans = 0;
int price;
up(i, 0, n)
{
x = read();
maxx = min(x, maxx);
}
int num = -1;
up(i, 0, m)
{
x = read();
if (x < maxx)continue;
num = max(num, x);
}
if (~num)
{
ans = (r - (r / maxx) * maxx) + (r / maxx) * num;
cout << ans << endl;
}
else cout << r << endl;
return 0;
}
B题
基础BFS
注意到这里我们每次拥有一个可以放的5格就一定要放。
因为可以直到从上到下,从左到右,如果有空格,那么一定是现在的一个可以放置的去填满这个空格。
所以对于每一个空格,bfs填满就行了。最后扫一遍看能否将整个图填满,也就是贪心。
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
int n;
const int N = 55;
char grp[N][N];
int dx[] = { 1,-1,0,0 };
int dy[] = { 0,0,-1,1 };
int main()
{
n = read();
up(i, 0, n)
{
cin >> grp[i];
}
up(i, 0, n)
{
up(j, 0, n)
{
if (grp[i][j] == '#')continue;
bool flag = true;
up(k, 0, 4)
{
int xx = i + dx[k];
int yy = j + dy[k];
if (xx<0 || xx>=n || grp[xx][yy] == '#'||yy<0||yy>=n)
{
flag = false;
break;
}
}
if (flag)
{
grp[i][j] = '#';
up(k, 0, 4)
{
int xx = i + dx[k];
int yy = j + dy[k];
grp[xx][yy] = '#';
}
}
}
}
up(i, 0, n)
{
up(j, 0, n)
{
if (grp[i][j] == '.')
{
// cout << "i" << i << 'j' << j << endl;
cout << "no" << endl;
return 0;
}
}
}
cout << "yes" << endl;
return 0;
}
C题。构造。
我们可以知道的是,素数除了2以外,都是偶数。所以一开始我们放置2,1,凑出奇数。
那么后面一直放2,可以凑出每一个素数,因为奇数加上偶数是奇数。剩下的放置1就行了。
两个1=一个2所以也是能凑出最远的那个素数的。就满足了题意。
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
int n;
const int N = 2e5 + 10;
int a[N];
int cnt = 0;
int main()
{
n = read();
int ones=0, twos=0;
int sum = 0;
up(i, 0, n)
{
a[i] = read();
if (a[i] == 1)
{
ones++;
}
else
twos++;
sum += a[i];
}
if (ones == 0)
up(i, 0, n)cout << a[i]<<" ";
else if (twos == 0)up(i, 0, n)cout << a[i]<<" ";
else {
cout << "2 1 ";
twos--, ones--;
if (twos)
{
while (twos--)
{
cout << "2 ";
}
while (ones--)
cout << "1 ";
}
else
{
while (ones--)cout << "1 ";
}
}
return 0;
}
D题
看了博客才会。
题目意思就是问是否能在原序列中剖出现在我们需要的这三个串。
我们维护dp[i][j][k]三位dp表示,三个串长度为i,j,k时,在原序列中至少要在那个位置才能被满足。
所以对于每一次询问。如果i的序列长度加了1,就有三种转移方式。
i长度不变,dp[i][j-1][k]+pos=dp[i][j][k]
j长度不变,和k长度不变。(i已经加1了,需要每一次都优先处理,即j,k不变,i-1)
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
int n, q;
int pos[30];
const int N = 1e5 + 10;
int pre[N][30];
int dp[300][300][300];
int d[5], p[5];
char st[3][300];
char s[N];
int l1, l2, l3;
string op;
void check(int x,char y)
{
if (x == 1)
{
l1++;
st[0][l1] = y;
// cout << l1 << l2 << endl;
upd(i, 0, l2)
{
upd(j, 0, l3)
{
//cout<<pre[dp[l1 - 1][i][j]][st[0][l1] - 'a'];
dp[l1][i][j] = pre[dp[l1 - 1][i][j]][st[0][l1] - 'a'];
if (i)dp[l1][i][j] = min(dp[l1][i][j], pre[dp[l1][i - 1][j]][st[1][i] - 'a']);
if (j)dp[l1][i][j] = min(dp[l1][i][j], pre[dp[l1][i][j - 1]][st[2][j] - 'a']);
}
}
}
if (x == 2)
{
l2++;
st[1][l2] = y;
upd(i, 0, l1)
{
upd(j, 0, l3)
{
dp[i][l2][j] = pre[dp[i][l2-1][j]][st[1][l2] - 'a'];
if (i)dp[i][l2][j] = min(dp[i][l2][j], pre[dp[i-1][l2][j]][st[0][i] - 'a']);
if (j)dp[i][l2][j] = min(dp[i][l2][j], pre[dp[i][l2][j - 1]][st[2][j] - 'a']);
}
}
}
if (x == 3)
{
l3++;
st[2][l3] = y;
upd(i, 0, l1)
{
upd(j, 0, l2)
{
dp[i][j][l3] = pre[dp[i][j][l3-1]][st[2][l3] - 'a'];
if (i)dp[i][j][l3] = min(dp[i][j][l3], pre[dp[i - 1][j][l3]][st[0][i] - 'a']);
if (j)dp[i][j][l3] = min(dp[i][j][l3], pre[dp[i][j - 1][l3]][st[1][j] - 'a']);
}
}
}
}
int main()
{
n = read();
q = read();
cin >> s+1;
up(i, 0, 26)pre[n+1][i] = n+1, pos[i] = n+1;
dwd(i, n , 0)
{
up(j, 0, 26)
{
pre[i][j] = pos[j];
if (s[i] - 'a' == j)
{
pos[j] = i;
}
}
}
while (q--)
{
cin >> op;
if (op[0] == '+')
{
int a; char b[2];
a = read(), cin >> b;
check(a,b[0]);
// cout <<"dp"<< dp[l1][l2][l3] << endl;;
if (dp[l1][l2][l3] <= n)
{
cout << "yes" << endl;
}
else
cout << "no" << endl;
}
else
{
int a;
a = read();
if (a == 1)l1--;
else if (a == 2)l2--;
else l3 -- ;
if (dp[l1][l2][l3] <= n)
{
cout << "yes" << endl;
}
else
cout << "no" << endl;
}
}
return 0;
}
E题
给出中序遍历,求树上最远两点距离。
一开始树状数组维护,发现不行,改用线段树,然后合并区间一堆错误。最后看博客慢慢才看明白究竟该怎么合并。感觉自己树上操作不够熟练。
这里我们运用公式,树上任一点为根节点的时候,都有 h[v]+h[u]-2h[lca(v,u)](树上差分)
所以我们找的就是让这个最大的值。
考虑(=1,)=-1 ,那么h到根的高度就是前缀和。
我们线段树来维护的是整个中序遍历出来的序列。意味着,根节点一定在[l,r ]之间,即[l,r]中深度最小点就是l和r的lca。
我们现在找的就是[l,r]中h[v]+h[u]-2h[lca[v,u]](l<=v<=u<=r)的最大值。那么让h[v]尽量大,同时维护h[lca[v,u]]小就行了。
我们可以知道这样的区间要么在整个左子树,要么在整个右子树,要么跨界。所以我们分别维护就好了。维护如果选最深点在左区间的时候,h[v]-2*h[lca]的最大值,然后就能跨到右区间了,同理右跨左。
注意左右子树合并的时候,需要计算高度。因为在原来的树中,相当于把右边的序列接到了左子树。
例如(()),右子树))的高度需要加上左子树((的高度2。(合并细节蛮多的,有些细节我还是没懂其实。。留个坑吧)
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
const int N = 2e5 + 10;
int n, q;
string s;
struct node
{
int height, amx, bmin, lmax, rmax,ans;
node(int height=0,int amx=0,int bmin=0,int lmax=0,int rmax=0,int ans=0):height(height),amx(amx),bmin(bmin),lmax(lmax),rmax(rmax),ans(ans){}
node operator+(const node&a)const
{
node temp;
temp.height = height + a.height;
temp.amx = max(amx, a.amx+height);
temp.bmin = min(bmin, a.bmin+height);
temp.lmax = max(max(lmax, a.lmax-height), amx - 2 * (a.bmin+height));
temp.rmax = max(max(rmax, a.rmax-height), a.amx-2*bmin+height);
temp.ans = max(max(ans, a.ans), max(lmax + a.amx + height, a.rmax + amx - height));
return temp;
}
}tree[4*N];
void build(int l,int r,int num)
{
if (l == r)
{
int k = s[l-1] == '(' ? 1 : -1;
tree[num].height = k;
tree[num].amx = tree[num].bmin = k;
tree[num].lmax = tree[num].rmax = -k;
tree[num].ans = 0;
return;
}
int mid = (l + r) >> 1;
build(l, mid, num << 1);
build(mid + 1, r, num << 1 | 1);
tree[num] = tree[num << 1] + tree[num << 1 | 1];
}
void build2(int l, int r, int k, int x)
{
if (l == r)
{
build(l, r, k);
return;
}
int mid = (l + r) >> 1;
if (x <= mid)build2(l, mid, k << 1, x);
else build2(mid + 1, r, k << 1 | 1, x);
tree[k] = tree[k << 1] + tree[k << 1 | 1];
}
void print(int l,int r,int k)
{
if (l == r) {
cout << tree[k].ans << endl;
return;
}
int mid = (l + r) >> 1;
print(l, mid, k<<1);
print(mid + 1, r, k << 1 | 1);
}
int main()
{
n = read();
q = read();
cin >> s;
n = 2 * (n - 1);
build(1, n, 1);
cout << tree[1].ans << endl;
//print(1,n,1);
int x, y;
while (q--)
{
x = read();
y = read();
x--, y--;
swap(s[x], s[y]);
build2(1, n, 1,x+1);
build2(1, n, 1, y + 1);
cout << tree[1].ans << endl;
}
return 0;
}