https://codeforces.com/contest/347
ZR的作业,来填填坑
A. Difference Row
睿智题,贪心最后面的最大,最前面的最小,中间排序就行了
// by Balloons
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() puts("okkkkkkkk")
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
typedef long long LL;
#define int LL
const int inf = 1 << 30;
const int maxn=11111;
int n;
int a[maxn],t[maxn];
int mn=inf,mx=-inf;
signed main(){
scanf("%I64d",&n);for(int i=1;i<=n;i++)scanf("%I64d",&a[i]),mn=min(mn,a[i]),mx=max(mx,a[i]);
if(n==1){printf("%I64d\n",a[1]);return 0;}
int ccc,cd;
for(int i=1;i<=n;i++){
if(mn==a[i])t[n]=a[i],ccc=i;
if(mx==a[i])t[1]=a[i],cd=i;
}
int cc=1;
for(int i=1;i<=n;i++){
if(ccc!=i&&cd!=i)t[++cc]=a[i];
}
sort(t+2,t+n);
for(int i=1;i<=n;i++)printf("%I64d ",t[i]);
return 0;
}
B. Fixed Points
睿智题,注意到答案是
p
[
i
]
=
=
i
p[i]==i
p[i]==i 的数的个数+
d
d
d,
0
≤
d
≤
2
0\le d\le 2
0≤d≤2,看是否存在
p
[
p
[
i
]
]
=
=
i
p[p[i]]==i
p[p[i]]==i的情况即可
// by Balloons
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() puts("okkkkkkkk")
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
typedef long long LL;
const int inf = 1 << 30;
const int maxn=2e5+5;
int n;
int a[maxn];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),++a[i];
int ans=0,mx=0;
for(int i=1;i<=n;i++){
if(a[i]==i){++ans;continue;}
if(mx==2)continue;
if(a[a[i]]==i){mx=2;continue;}
else mx=1;
}
printf("%d\n",ans+mx);
return 0;
}
C. Alice and Bob
注意最终情况就是形成了一个等差数列
发现操作特别像辗转相减的过程,大胆猜测最终最小的那个数一定是gcd{a[i]}
根据辗转相除的结论,最终 set 里面所有的数一定都是 gcd{a[i]} 的倍数,这就有了公差
因此可以根据a[i] 中最大的数算出项数,-n (set里面本来就有n个数) 看奇偶性即可
项数就是要到达输的状态的次数
// by Balloons
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() puts("okkkkkkkk")
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
typedef long long LL;
const int inf = 1 << 30;
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int n;
int a[111111];
int main(){
int gd=0,mx=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),gd=gcd(gd,a[i]),mx=max(mx,a[i]);
int xs=(mx-gd)/gd+1-n;
if(xs&1)puts("Alice");
else puts("Bob");
return 0;
}
D. Lucky Common Subsequence
辣鸡dp,毁我青春
这题状态和前两个转移都非常好考虑,主要在于第三个
令
d
p
[
i
]
[
j
]
[
k
]
dp[i][j][k]
dp[i][j][k]表示考虑到
A
[
1..
i
]
,
B
[
1..
j
]
A[1..i], B[1..j]
A[1..i],B[1..j]的公共子序列与
v
i
r
u
s
[
1..
k
]
virus[1..k]
virus[1..k]相同时长度的最大值
d
p
[
i
+
1
]
[
j
]
[
k
]
=
m
a
x
{
d
p
[
i
+
1
]
[
j
]
[
k
]
,
d
p
[
i
]
[
j
]
[
k
]
}
dp[i+1][j][k]=max\{ dp[i+1][j][k], \ dp[i][j][k] \}
dp[i+1][j][k]=max{dp[i+1][j][k], dp[i][j][k]}
d
p
[
i
]
[
j
+
1
]
[
k
]
=
m
a
x
{
d
p
[
i
]
[
j
+
1
]
[
k
]
,
d
p
[
i
]
[
j
]
[
k
]
}
dp[i][j+1][k]=max\{ dp[i][j+1][k], \ dp[i][j][k] \}
dp[i][j+1][k]=max{dp[i][j+1][k], dp[i][j][k]}
d
p
[
i
+
1
]
[
j
+
1
]
[
w
]
=
m
a
x
{
d
p
[
i
+
1
]
[
j
+
1
]
[
w
]
,
d
p
[
i
]
[
j
]
[
k
]
}
dp[i+1][j+1][w]=max\{ dp[i+1][j+1][w], \ dp[i][j][k] \}
dp[i+1][j+1][w]=max{dp[i+1][j+1][w], dp[i][j][k]},其中
w
w
w就是匹配到的
C
C
C的位置
然后记录一下每个转移到的位置,最后dfs一下就可以啦
代码:
// by Balloons
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() puts("okkkkkkkk")
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
typedef long long LL;
const int inf = 1 << 30;
const int maxn=111;
struct data{int x,y,z;}pre[maxn][maxn][maxn],e;
char a[maxn],b[maxn],c[maxn];
int dp[maxn][maxn][maxn],nxt[maxn];
int na,nb,nc;
void getnx(){
nxt[0]=0;
int j=0;
for(int i=1;i<nc;i++){
for(;c[j]!=c[i]&&j>0;j=nxt[j-1]);
if(c[j]==c[i])++j;
nxt[i]=j;
}
}
void dfs(data cur){
int cx=cur.x,cy=cur.y,cz=cur.z;
if(cx==cy&&cy==cz&&cz==0)return ;
data ch=pre[cx][cy][cz];
dfs(ch);
int hx=ch.x,hy=ch.y,hz=ch.z;
if(dp[hx][hy][hz]+1==dp[cx][cy][cz])printf("%c",a[hx]);
}
int main(){
scanf("%s",a);scanf("%s",b);scanf("%s",c);
memset(dp,0,sizeof dp);
na=strlen(a);nb=strlen(b);nc=strlen(c);
getnx();
for(int i=0;i<=na;i++)for(int j=0;j<=nb;j++)dp[i][j][0]=0;
for(int i=0;i<=na;i++){
for(int j=0;j<=nb;j++){
for(int k=0;k<nc;k++){
if(dp[i+1][j][k]<dp[i][j][k]){
dp[i+1][j][k]=dp[i][j][k];
pre[i+1][j][k].x=i;
pre[i+1][j][k].y=j;
pre[i+1][j][k].z=k;
}
if(dp[i][j+1][k]<dp[i][j][k]){
dp[i][j+1][k]=dp[i][j][k];
pre[i][j+1][k].x=i;
pre[i][j+1][k].y=j;
pre[i][j+1][k].z=k;
}
if(a[i]==b[j]){
int w=k;
//**********
for(;a[i]!=c[w]&&w>0;w=nxt[w-1]);
if(a[i]==c[w])++w;
else w=0;
//**********
if(dp[i+1][j+1][w]<dp[i][j][k]+1){
dp[i+1][j+1][w]=dp[i][j][k]+1;
pre[i+1][j+1][w].x=i;
pre[i+1][j+1][w].y=j;
pre[i+1][j+1][w].z=k;
}
}
// printf("%d \n",dp[i][j][k]);
}
}
}
int mx=0;
for(int k=0;k<nc;k++){
if(dp[na][nb][k]>mx){
mx=dp[na][nb][k];
e.x=na;e.y=nb;e.z=k;
}
}
if(mx==0)return puts("0"),0;
dfs(e);
return 0;
}
E. Number Transformation II
比D简单
贪心一下,每次加到set里面就行了
// by Balloons
#include <cstdio>
#include <set>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() puts("okkkkkkkk")
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
typedef long long LL;
const int inf = 1 << 30;
set<int>S;
int n;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
S.insert(x);
}
int ans=0,a,b;scanf("%d%d",&a,&b);
while(a>b){
set<int>T=S;
int tmpa=a-1;
// if(S.empty())debug();
for(set<int>::iterator it = S.begin(); it != S.end(); it ++ ){
int x=*it;
// printf("FF %d %d\n",a-a%x,S.size());
if(a-a%x<b)T.erase(x);
else tmpa=min(tmpa,a-a%x);
if(S.empty())break;
}
ans++;
a=tmpa;
S=T;
// printf("%d\n",a);
}
printf("%d\n",ans);
return 0;
}