https://codeforces.com/contest/347
ZR的作业,来填填坑
A. Difference Row
睿智题,贪心最后面的最大,最前面的最小,中间排序就行了
// by Balloons
#include
#include
#include
#include
#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
#include
#include
#include
#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
#include
#include
#include
#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
#include
#include
#include
#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
#include
#include
#include
#include
#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;
}