D. Suitable Replacement
题意:把 S串中的?转化为小写字母,使得字符串 S拥有最多的 字符串T的不相交字串,(S中的字母可以互换顺序)
题解:贪心
#include<bits/stdc++.h>
#define mp make_pair
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef long double ld;
const int N=1e7+10;
const int MAXN=20010;
const int INF=0x3f3f3f3f;
const double eps=0.0000001;
const ll mod=1e9+7;
int n,m,x,y,t;
char a[N],b[N],c[N];
int num[N];
int main()
{
scanf("%s",a);
scanf("%s",b);
int len1=strlen(a),len2=strlen(b);
int cnt=0;
for(int i=0;i<len1;i++)
{
if(a[i]=='?') cnt++;
else num[a[i]-'a']++;
}
int p=0,flag=0;
while(1)
{
for(int i=0;i<len2;i++)
{
if(num[b[i]-'a']>0)
num[b[i]-'a']--;
else
{
if(cnt>0)
{
cnt--;
c[p++]=b[i];
}
else
flag=1;
}
}
if(flag==1) break;
}
p=0;
for(int i=0;i<len1;i++)
{
if(a[i]=='?') printf("%c",c[p++]);
else printf("%c",a[i]);
}
}
D. Welfare State
题意:
有 n个人,下面一行是每个人的钱,一共 q个操作。
1 操作:是把第i个人的钱数变成
x
x
x
2 操作:是把所有钱数小于
x
x
x的变成
x
x
x。
题解:简单模拟,详见代码
#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef long double ld;
const int N=1e7+10;
const int MAXN=20010;
const int INF=0x3f3f3f3f;
const double eps=0.0000001;
const ll mod=1e9+7;
int n,m,x,y,t;
int a[N],b[N];
pair<int,pii>p[N];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d",&p[i].fi);
if(p[i].fi==1)
scanf("%d%d",&p[i].se.fi,&p[i].se.se);
else
scanf("%d",&p[i].se.se);
}
int temp=0;
///因为处理的是最后一次,又因为 1操作后的二操作会影响 a[i]的值所以选择倒序
for(int i=m;i>=1;i--)
{
if(p[i].fi==1&&b[p[i].se.fi]==0)///仅处理 1操作的最后一次即可
{
b[p[i].se.fi]=1;
a[p[i].se.fi]=max(temp,p[i].se.se);
}
if(p[i].fi==2)///找到最大二操作
{
temp=max(temp,p[i].se.se);
}
}
for(int i=1;i<=n;i++)
{
if(b[i]!=1) a[i]=max(temp,a[i]);
printf("%d ",a[i]);
}
}
D. Yet Another Subarray Problem
题意:
给出一列数组和两个常数
m
,
k
m,k
m,k,然后定义一段子序列的
c
o
s
t
cost
cost等于该段子序列各元素之和减去该段长度与
m
m
m之商的向上取整的值与
k
k
k的乘积。求任取一段连续子序列所能得到的最大的
c
o
s
t
cost
cost。(
p
s
ps
ps:可以取空集,此时子序列的
c
o
s
t
cost
cost为
0
0
0)
题解:(动态规划)
d
p
[
i
]
dp[i]
dp[i]表示,以
i
i
i结尾的连续子序列的
c
o
s
t
cost
cost值
dp[i]有两种转移方式:
第一种是:当
(
l
−
r
)
(l-r)
(l−r)<=
m
m
m时
(
[
i
−
x
,
i
]
[i-x,i]
[i−x,i]的区间和)
−
-
−
k
k
k 的最大值
(
0
(0
(0<=
x
x
x<=
m
)
m)
m)
第二种是:当
(
l
−
r
)
(l-r)
(l−r)>
m
m
m时
(
[
i
−
m
,
i
]
[i-m,i]
[i−m,i]的区间和)
−
-
−
k
k
k
+
+
+(以
i
−
m
i-m
i−m结尾的连续子序列的
c
o
s
t
cost
cost值)
#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef long double ld;
const int N=10e5+10;
const int MAXN=20010;
const ll MAX=2e18;
const int INF=0x3f3f3f3f;
const double eps=0.0000001;
const ll mod=1e9+7;
ll n,m,x,y,t,k,p,ans;
ll dp[N],a[N],sum[N];
int main()
{
scanf("%lld%lld%lld",&n,&m,&k);
memset(dp,-INF,sizeof(dp));
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]),sum[i]=sum[i-1]+a[i];
for(int i=1;i<=n;i++)
{
for(int j=max(1ll,i-m+1);j<=i;j++)
dp[i]=max(dp[i],sum[i]-sum[j-1]-k);
dp[i]=max(dp[i],dp[max(0ll,i-m)]+sum[i]-sum[max(0ll,i-m)]-k);
ans=max(ans,dp[i]);
}
printf("%lld",ans);
}
D. Subarray Sorting
题意:
给定一个数组
a
1
a
2
…
a
n
a_1 a_2…a_n
a1a2…an和一个数组
b
1
b
2
…
b
n
b_1 b_2…b_n
b1b2…bn。
对于一个操作,您可以按非递减顺序对数组
a
a
a的任何子数组
a
[
l
…
r
]
a[l…r]
a[l…r]排序。
例如,如果
a
=
[
4
,
2
,
2
,
1
,
3
,
1
]
a=[4,2,2,1,3,1]
a=[4,2,2,1,3,1],然后选择
s
u
b
b
a
r
r
a
y
subbarray
subbarray
a
[
2
…
5
]
a[2…5]
a[2…5],那么数组就变成
[
4
,
1
,
2
,
2
,
3
,
1
]
[4,1,2,2,3,1]
[4,1,2,2,3,1]。
要求您确定是否可以通过对数组
a
a
a应用任意次数的这个操作(可能为零)来获得数组
b
b
b。
题解:(排序的本质就是两两交换)树状数组求解区间最值
如果
b
i
b_i
bi可以通过排序操作取得,
b
i
b_i
bi那么一定是某段区间的最小值,所以接下来就确定这个区间的范围,如果前
i
−
1
i-1
i−1项都匹配好了,易知这个范围大致就是
[
i
,
a
n
s
]
[i,ans]
[i,ans]
a
n
s
ans
ans=
(
b
i
(b_i
(bi在
a
a
a中第一个未匹配的下标
)
)
)。
例如题目给的例子,
b
2
b_2
b2的范围就是
[
2
,
4
]
[2,4]
[2,4],然后将数组
a
=
[
4
,
2
,
2
,
1
,
3
,
1
]
a=[4,2,2,1,3,1]
a=[4,2,2,1,3,1],改为
a
=
[
4
,
1
,
2
,
2
,
3
,
1
]
a=[4,1,2,2,3,1]
a=[4,1,2,2,3,1]再进行下一步,但这样操作很花时间,所以考虑不改变
a
a
a数组的顺序,因为求的是区间最值,所以如果这个数已经匹配好了,那么就把这个数删去,进行下一操作时在询问区间
[
1
,
a
n
s
]
[1,ans]
[1,ans]最值就好了,y因为询问
i
i
i,前面删了
i
−
1
i-1
i−1个数,所以等价于上面的
[
i
,
a
n
s
]
[i,ans]
[i,ans]。
最后区间最小值用线段树或者树状数组维护一下就好了。
#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int N=3e5+10;
const int MAXN=20010;
const LL MAX=2e18;
const int INF=0x3f3f3f3f;
const double eps=0.0000001;
const LL mod=1e9+7;
int n,m,x,y,t,k,p,ans;
int a[N], h[N],b[N];
int lowbit(int x)
{
return x & (-x);
}
void updata(int x)
{
int lx, i;
while (x <= n)
{
h[x] = a[x];
lx = lowbit(x);
for (i=1; i<lx; i<<=1)
h[x] = min(h[x], h[x-i]);
x += lowbit(x);
}
}
int query(int x, int y)
{
int ans = INF;
while (y >= x)
{
ans = min(a[y], ans);
y --;
for (; y-lowbit(y) >= x; y -= lowbit(y))
ans = min(h[y], ans);
}
return ans;
}
queue<int>id[N];
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
while(!id[i].empty()) id[i].pop();
}
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
id[a[i]].push(i);
}
for(int i=1;i<=n;i++) updata(i);
int flag=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
if(id[b[i]].empty()) flag=1;
if(flag!=1)
{
int sx=id[b[i]].front();
id[b[i]].pop();
if(query(1,sx)<b[i]) flag=1;
else
{
a[sx]=n+1;
updata(sx);
}
}
/*for(int i=1;i<=n;i++)
printf("%d ",h[i]);
printf("\n");*/
}
flag?printf("NO\n"):printf("YES\n");
}
}