概述
骗阅读量
B
题意:给定两个整数序列A,B,找出一种括号方案,对于每一对匹配的括号i,j,贡献为
m
a
x
(
A
i
+
A
j
,
B
i
+
B
j
)
max(A_i+A_j,B_i+B_j)
max(Ai+Aj,Bi+Bj),找出最大贡献和
1
⩽
n
⩽
1
0
5
1leqslant n leqslant 10^5
1⩽n⩽105
做法:钦定哪些位置是A,哪些为B
那么存在方案的等价条件是:B在原序列占有的奇偶位置数量一样
然后借此贪心即可
P,Q 如果P,那么Q Q是P的必要条件 P是Q的充分条件
proof:首先这肯定是个必要条件
接下来我们证明这是个充分条件
如果我们给出B括号的一种匹配方案,对于每一对匹配的i,j(i<j),如果我们满足
2
∣
j
−
i
−
1
2|j-i-1
2∣j−i−1,那么就对了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
#define Maxn 100010
int A[Maxn],B[Maxn];
int seq1[Maxn],seq2[Maxn];
bool vis[Maxn];
int main(){
ll Ans=0;
cin>>n;
for(int i=1;i<=n;++i)cin>>A[i],Ans+=A[i];
for(int i=1;i<=n;++i){
cin>>B[i];
B[i]-=A[i];
if(i&1)seq1[i/2+1]=B[i];
else seq2[i/2]=B[i];
}
sort(seq1+1,seq1+n/2+1);sort(seq2+1,seq2+n/2+1);
for(int i=n/2;i>=1;--i)Ans+=max(0,seq1[i]+seq2[i]);
printf("%lldn",Ans);
return 0;
}
D
题意:多组数据,n堆石子,A和B轮流玩游戏,A每次从最左边石子堆中取若干石子,B从最右边取,取不了就是输的。
T
⩽
100
,
n
⩽
100
,
A
i
⩽
1
0
9
Tleqslant 100,nleqslant 100,A_i leqslant 10^9
T⩽100,n⩽100,Ai⩽109
如果先手赢的话,那么对于
A
′
1
>
=
A
1
A'1>=A_1
A′1>=A1的石子序列
A
′
1
A
2
A
3
.
.
.
A
n
A'1A_2A_3...A_n
A′1A2A3...An,仍然是先手先赢,策略可以照搬
我们再观察下整个博弈的过程,发现可以设计出这么一个dp
F
0
i
,
j
,
k
F_0{i,j,k}
F0i,j,k表示仅考虑i到j的石子堆,先手从左边开始取,且最左边只剩下k个(而不是
A
i
A_i
Ai个),
k
⩽
A
i
k leqslant A_i
k⩽Ai,先手能否赢
F
1
i
,
j
,
k
F_1{i,j,k}
F1i,j,k表示仅考虑i到j的石子堆,先手从右边开始取,且最右边只剩下k个(而不是
A
j
A_j
Aj个),
k
⩽
A
j
kleqslant A_j
k⩽Aj,先手能否赢
所以我们得到个区间dp
根据刚才的观察
f
j
z
i
,
j
,
0
=
n
u
m
fjz_{i,j,0}=num
fjzi,j,0=num先手左边,最左边石子数<=num即会失败,否则会成功
f
j
z
i
,
j
,
1
fjz_{i,j,1}
fjzi,j,1差不多
dp过程略
#include<bits/stdc++.h>
using namespace std;
int n;
#define Maxn 105
int A[Maxn];
int fjz[Maxn][Maxn][2];
inline void rd(int &x){
x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
}
int main(){
int T;
rd(T);
while(T--){
rd(n);
for(int i=1;i<=n;++i)rd(A[i]);
for(int i=1;i<=n;++i)fjz[i][i][0]=fjz[i][i][1]=0;
for(int len=2;len<=n;++len)
for(int i=1;i<=n-len+1;++i){
int j=i+len-1;
//fjz[i][j-1][0] fjz[i+1][j][1]
if(fjz[i][j-1][0]==A[i])fjz[i][j][1]=0;
else fjz[i][j][1]=min(fjz[i+1][j][1]+A[i]-fjz[i][j-1][0],A[j]);
//fjz[i+1][j][1] fjz[i][j-1][0]
if(fjz[i+1][j][1]==A[j])fjz[i][j][0]=0;
else fjz[i][j][0]=min(fjz[i][j-1][0]+A[j]-fjz[i+1][j][1],A[i]);
}
if(A[1]>fjz[1][n][0])puts("First");
else puts("Second");
}
return 0;
}
E
题意:不想说了。。。。。。
解法:官方题解不是很详细。我这个更加简略
通过画图像,当你前i个确定好x(不考虑后面),满足仅考虑前i个限制,后面一定会有对应的方案,这启示我们贪心。
像题解那样,令
z
i
=
A
i
+
T
∗
x
i
z_i=A_i+T*x_i
zi=Ai+T∗xi,那么有
z
i
<
=
A
1
−
T
z_i<=A_1-T
zi<=A1−T或
z
i
>
A
1
z_i>A_1
zi>A1,证明参考上面的贪心
然后通过这个,我们可以构造出
A
2
A_2
A2到
A
n
A_n
An的x,然后对于
z
i
′
>
A
1
−
T
z'_i>A_1-T
zi′>A1−T的,
x
i
=
x
i
′
+
1
x_i=x'_i+1
xi=xi′+1
然后就随便dp了,我写的是
O
(
n
K
l
o
g
2
K
+
n
3
K
)
O(nKlog_2K+n^3K)
O(nKlog2K+n3K)的做法
#include<bits/stdc++.h>
using namespace std;
const int Mod=1000000007;
int n,T,K;
#define Maxn 52
int B[Maxn][Maxn];
int A[Maxn][Maxn][Maxn][Maxn];
int Ans[Maxn];
namespace modular{
int add(int a,int b){return a+b>=Mod?a+b-Mod:a+b;}
int mul(int a,int b){return 1ll*a*b%Mod;}
void Add(int &a,int b){a=a+b>=Mod?a+b-Mod:a+b;}
}using namespace modular;
inline void rd(int &x){
x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
}
int main(){
rd(n);rd(K);rd(T);
for(int i=1;i<=n;++i){
for(int j=1;j<=K;++j)rd(B[i][j]);
sort(B[i]+1,B[i]+K+1);
}
for(int i=1;i<=K;++i)A[n][n][i][0]=1;
int Kpow=1;
for(int i=n;i>=2;--i){
Kpow=mul(Kpow,K);
for(int j=i;j<=n;++j)
for(int l=0;l<=n-i;++l){
int at=0;
for(int k=1;k<=K;++k){
int t=A[i][j][k][l];
while(at<K&&B[i-1][at+1]-T<B[j][k]+l*T)at++;
Add(A[i-1][j][k][l+1],mul(t,at));
Add(A[i-1][j][k][l],mul(t,K-at));
}
}
for(int j=1;j<=K;++j)A[i-1][i-1][j][0]=Kpow;
}
for(int i=1;i<=n;++i){
Ans[i]=0;
for(int j=1;j<=K;++j)
for(int l=0;l<n;++l)Add(Ans[i],mul(A[1][i][j][l],l));
printf("%dn",Ans[i]);
}
return 0;
}
最后
以上就是勤恳冥王星为你收集整理的agc 048部分题解的全部内容,希望文章能够帮你解决agc 048部分题解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复