【解题报告】CF DIV2 #ROUND 718 A~D

​比赛链接​​​ 突然想起来自己上周打的还没补完题目(大雾)
开的虚拟,不算如意的一场,又被B题卡了,5分钟切A然后B卡很久都没写出来,后面花了20来分钟切C,5000+排名

A. Sum of 2050

思路
看有没有解直接看能不能整除就行,最少需要多少,看成2050进制数,把每位加起来即可
代码

// Problem: A. Sum of 2050
// Contest: Codeforces - Contest 2050 and Codeforces Round #718 (Div. 1 + Div. 2)
// URL: https://codeforces.com/contest/1517/problem/A
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// FishingRod

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
#define MULINPUT
/*DATA & KEY
t 1 1000
n 1 1e18
*/
int T;
void solve(int C)
{
//NEW DATA CLEAN

//NOTE!!!
LL n;cin>>n;
LL ans=0;
if(n%2050==0)
{
LL k=n/2050;
while(k)
{
ans+=k%10;
k/=10;
}
cout<<ans<<endl;
}
else puts("-1");


}

int main()
{
#ifdef MULINPUT
scanf("%d",&T);
for(int i=1;i<=T;i++)solve(i);
#else
solve(1);
#endif
return 0;
}

B. Morning Jogging

【解题报告】CF DIV2 #ROUND 718 A~D_i++

思路
模拟题,但谜之写不出来,​​参考这位大佬的题解​​ 先把所有数里最小的m个确定下来,,其他的该在哪组就放在哪组
开个结构体把原来位置记录下来
代码

// Problem: B. Morning Jogging
// Contest: Codeforces - Contest 2050 and Codeforces Round #718 (Div. 1 + Div. 2)
// URL: https://codeforces.com/contest/1517/problem/B
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// FishingRod

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
#define MULINPUT
/*DATA & KEY

*/
int T;
const int N=105;
struct Node{int x,y,w;}r[N*N];
bool vis[N][N];
int ans[N][N],u[N][N],b[N][N];
bool cmp(Node a,Node b){return a.w<b.w;}
void solve(int C)
{
//NEW DATA CLEAN
memset(r,0,sizeof r);
memset(vis,0,sizeof vis);
memset(u,0,sizeof u);
memset(ans,0,sizeof ans);
memset(b,0,sizeof b);
//NOTE!!!
int n,m;cin>>n>>m;
int cnt=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>r[++cnt].w;
r[cnt].x=i;
r[cnt].y=j;
b[i][j]=r[cnt].w;
}
sort(r+1,r+1+cnt,cmp);
for(int i=1;i<=m;i++)
{
ans[r[i].x][i]=r[i].w;
vis[r[i].x][r[i].y]=1;//标记已经用掉的
}

for(int i=1;i<=n;i++)
{
int cnt=0;
for(int j=1;j<=m;j++)
{
if(!vis[i][j])u[i][++cnt]=b[i][j];//u存储可以用的
}
}

for(int i=1;i<=n;i++)
{
int cnt=0;
for(int j=1;j<=m;j++)
{
if(!ans[i][j])ans[i][j]=u[i][++cnt];
}
}

for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cout<<ans[i][j]<<" ";
if(j==m)puts("");
}
}

int main()
{
#ifdef MULINPUT
scanf("%d",&T);
for(int i=1;i<=T;i++)solve(i);
#else
solve(1);
#endif
return 0;
}

C - Fillomino 2

思路
答案一定有解,按照最优方法放置,先试试放左边,不行的话放下面。dfs实现即可
代码

// Problem: C. Fillomino 2
// Contest: Codeforces - Contest 2050 and Codeforces Round #718 (Div. 1 + Div. 2)
// URL: https://codeforces.com/contest/1517/problem/C
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// FishingRod

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
//#define MULINPUT
/*DATA & KEY

*/
int T;
const int N=510;
int g[N][N];
bool st[N][N];
int k;//放外面而不是作为参数
void dfs(int x,int y,int w)
{
if(k==0)return;
if(x<1||y<1||x<y||st[x][y])return;
g[x][y]=w;k--;
st[x][y]=1;
dfs(x,y-1,w);
dfs(x+1,y,w);
}
void solve(int C)
{
//NEW DATA CLEAN

//NOTE!!!
int n;cin>>n;
for(int i=1;i<=n;i++)cin>>g[i][i];
for(int i=1;i<=n;i++)
{
int w=g[i][i];k=w;
dfs(i,i,w);
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)cout<<g[i][j]<<" ";
puts("");
}
}

int main()
{
#ifdef MULINPUT
scanf("%d",&T);
for(int i=1;i<=T;i++)solve(i);
#else
solve(1);
#endif
return 0;
}

D. Explorer Space

【解题报告】CF DIV2 #ROUND 718 A~D_i++_02

思路

非常规输入,先搞明白输入吧。大概就是先告诉你横向边的边长,然后再告诉你纵向边的边长

【解题报告】CF DIV2 #ROUND 718 A~D_i++_03


样例

【解题报告】CF DIV2 #ROUND 718 A~D_i++_04

然后这题要干嘛呢?求出从(i,j)出发走k步,然后回到(i,j)经过路径和最小多少
那我们写个DP呗
状态表示
【解题报告】CF DIV2 #ROUND 718 A~D_#endif_05
状态计算
直接四个方向状态转移就可以了呀懒得写了
初始状态
【解题报告】CF DIV2 #ROUND 718 A~D_#endif_06
目标状态
【解题报告】CF DIV2 #ROUND 718 A~D_#define_07折返了,因为可以重复走没影响那就反复走最小的路呗
答案直接乘2就可以了
如果是奇数就不可行输出-1
代码

// Problem: D. Explorer Space
// Contest: Codeforces - Contest 2050 and Codeforces Round #718 (Div. 1 + Div. 2)
// URL: https://codeforces.com/contest/1517/problem/D
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// FishingRod

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
//#define MULINPUT
/*DATA & KEY

*/
int T;
int n,m,k;
const int N=505;
map<PII,int>g;//用map不用g[N*N][N*N],不然爆空间
LL f[N][N][50];
int get_id(int x,int y){return (x-1)*m+y;}
bool check(int x,int y){if(x>=1&&x<=n&&y>=1&&y<=m)return 1;return 0;}
LL work(int x,int y,int s)//递归记忆化求解最值,这个写得比较少,记录一下
{
if(f[x][y][s])return f[x][y][s];
if(s==0)return f[x][y][0];
LL tmp=1e18+7;//先设置一个临时变量极大值
int u=get_id(x,y);
if(check(x-1,y))tmp=min(tmp,work(x-1,y,s-1)+g[{u,get_id(x-1,y)}]);
if(check(x+1,y))tmp=min(tmp,work(x+1,y,s-1)+g[{u,get_id(x+1,y)}]);
if(check(x,y-1))tmp=min(tmp,work(x,y-1,s-1)+g[{u,get_id(x,y-1)}]);
if(check(x,y+1))tmp=min(tmp,work(x,y+1,s-1)+g[{u,get_id(x,y+1)}]);
return f[x][y][s]=tmp;//把临时变量作为答案,而不是直接f[x][y][s]放到min里
}
void solve(int C)
{
//NEW DATA CLEAN

//NOTE!!!
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<m;j++)
{
LL w;cin>>w;
int u=get_id(i,j),v=get_id(i,j+1);//权不是点,而是边,可以二维转一维
g[{u,v}]=g[{v,u}]=w;
}
for(int i=1;i<n;i++)
for(int j=1;j<=m;j++)
{
LL w;cin>>w;
int u=get_id(i,j),v=get_id(i+1,j);
g[{u,v}]=g[{v,u}]=w;
}
if(k&1)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
printf("-1 ");
if(j==m)puts("");
}
return;
}

for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cout<<2*work(i,j,k/2)<<" ";
if(j==m)puts("");
}
}

int main()
{
#ifdef MULINPUT
scanf("%d",&T);
for(int i=1;i<=T;i++)solve(i);
#else
solve(1);
#endif
return 0;
}

反思

A:

手速手速手速

B:

模拟题好像只能多练了,在必要的时候把原来信息(如左边都存下来)

C:

水题,貌似也没啥好讲的

D:

递归+记忆化求解最值:先设置临时变量存储所有转移最小答案,最终赋值f[x][y][[s]
折返找最小路径,如果已经走过的点是没有影响的话,那么直接重复两次最小路径即可,把目标状态设为一半
点-边权-点存图
法一:可以二维转一维+map优化空间(如果开数组注意转一维后N*N,而不是N)
顺便,二维转一维度的时候

(x-1)*m+y,不是(x-1)*n+y啊啊啊!

法二:横向边权和纵向边权分开存,转移的时候用不同的边权数组转移