目录
A 夺宝奇兵
【题目】
【解题思路】
签到题。因为需要依次获得1-n类的宝藏再以n-1的顺序获得剩下的宝藏。因为最后两类宝藏Na和Nb之间的距离是一定的,所以只需求min(dis((N-1)a,Na)+dis((N-1)b,Nb),dis((N-1)b,Na)+dis((N-1)a,Nb))。这样从后往前求即可。
【代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=1e5+5;
struct Node
{
int x,y;
}a[maxn],b[maxn];
LL dis(Node A,Node B)
{
return (abs(A.x-B.x)+abs(A.y-B.y));
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d%d%d%d",&a[i].x,&a[i].y,&b[i].x,&b[i].y);
LL ans=dis(a[n],b[n]);
for(int i=n;i>=2;i--)
ans+=min(dis(a[i],a[i-1])+dis(b[i],b[i-1]),dis(a[i],b[i-1])+dis(b[i],a[i-1]));
printf("%lld\n",ans);
}
C 最小边覆盖
【题目】
【解题思路】
只要理解题目这就是道很容易的题了qwq然而比赛的时候我们被什么带花树算法、Gallai定理吓跑了...
最小边覆盖通俗来讲就是每个顶点只能被一条边想连。所以只需要计算每个顶点的度,当想连的两个顶点的度都>=2时说明不只有一条边与这两个顶点想连,所以这条边是可以被删去的,只要有可以被删去的边,这个边集就不是最小边覆盖。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int in[maxn],a[maxn],b[maxn];
int main()
{
int n,m,flag=1;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
scanf("%d%d",&a[i],&b[i]);
in[a[i]]++;
in[b[i]]++;
}
for(int i=0;i<m;i++)
{
if(in[a[i]]>1 && in[b[i]]>1)
{
flag=0;
break;
}
}
if(flag)printf("Yes\n");
else printf("No\n");
}
F 小小马
【题目】
【解题思路】
这题比赛的时候居然做了超级久……我犹记的那天不知道为什么我们的脑子的十分混乱
仔细分析一下其实还是简单的。稍微模拟一下就可以知道马当前所在的格子和它下一步跳的格子的奇偶性肯定不同,所以马跳跃的规律就是奇偶奇偶……不断交叉,所以使得经过的白点和黑点一样多只需要起始位置和终止位置的奇偶性不同即可。
手动画一下就好了,只要棋盘>=3*4的时候,每个位置都能够跳到,所以只需判断起始位置和终止位置奇偶性是否不同。<3*4的情况其实自己列一下就好了,我们当时真的混乱到懒得列就写了个暴力。
【代码】
#include<bits/stdc++.h>
const int maxn=200100;
using namespace std;
typedef long long LL;
int sx,ex;
int sy,ey;
int n,m,flag;
int vis[10][10];
int dirx[]={-2,-2,-1,-1,1,1,2,2};
int diry[]={-1,1,-2,2,-2,2,-1,1};
void dfs(int x,int y)
{
if(flag)return;
if(x==ex && y==ey)
{
flag=1;
return;
}
for(int i=0;i<8;i++)
{
int xx=dirx[i]+x;
int yy=diry[i]+y;
if(!vis[xx][yy] && xx>=1 && xx<=n &&yy>=1 && yy<=m)
{
vis[xx][yy]=1;
dfs(xx,yy);
vis[xx][yy]=0;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
scanf("%d%d",&sx,&sy);
scanf("%d%d",&ex,&ey);
int f1=0,f2=0;
if(sx%2==sy%2)f1=1;
if(ex%2==ey%2)f2=1;
if(f1==f2)printf("No\n");
else
{
if(n>=4&&m>=3)printf("Yes\n");
else
{
flag=0;
dfs(sx,sy);
if(flag)printf("Yes\n");
else printf("No\n");
}
}
}
G 置置置换
【题目】
【解题思路】
设dp[i][j]为长度为i的序列最后一个数字为j的方案数。
(1) 当i为奇数时:
对于第i这个位置是处于山峰的,而dp[i-1][j]中肯定没有出现过i(长度为i-1的排列块肯定不会出现i的),所以只要由dp[i-1][j](j<i)的所有状态转移过来即可,因为新加入的数i肯定是长度为i-1这个序列中最大的。所以:
dp[i][1]=0
dp[i][2]=dp[i-1][1]
dp[i][3]=dp[i-1][1]+dp[i-1][2]
dp[i][4]=dp[i-1][1]+dp[i-1][2]+dp[i-1][3]
……
用前缀和优化一下可以得到dp[i][j]=dp[i][j-1]+dp[i-1][j-1](1<=j<=i)
(2) 当i为偶数时:
对于第i这个位置是处于山谷的,所以dp[i][i]=0(i这个数肯定不能排在最后),那么dp[i][j]可以看做由dp[i][k](j<=k<=i-1)中所有大于等于j的数字+1转移过来,比如dp[4][2]由dp[3][2](3 1 2)和dp[3][3](2 1 3)转移,即相当于原来的序列变为(4 1 3 2)和(3 1 4 2)。所以(i=4):
dp[i][4]=0
dp[i][3]=dp[i-1][3]
dp[i][2]=dp[i-1][2]+dp[i-1][3]
dp[i][1]=dp[i-1][1]+dp[i-1][2]+dp[i-1][3]
最后前缀和优化得到dp[i][j]=dp[i][j+1]+dp[i-1][j]
【代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int Mod=1e9+7;
LL dp[1005][1005];
int main()
{
int n;
LL ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
dp[1][i]=1;
for(int i=2;i<=n;i++)
{
if(i%2)
{
dp[i][1]=0;
for(int j=2;j<=i;j++)
dp[i][j]=(dp[i][j-1]+dp[i-1][j-1])%Mod;
}
else
{
dp[i][i]=0;
for(int j=i-1;j>=1;j--)
dp[i][j]=(dp[i][j+1]+dp[i-1][j])%Mod;
}
}
for(int i=1;i<=n;i++)
ans=(ans+dp[n][i])%Mod;
printf("%lld\n",ans);
}
I 咆咆咆哮
【题目】
【解题思路】
贪心。枚举召唤生物的个数,预处理排序,因为要使攻击值达到最大,肯定是先把需要的生物数量召唤好,再出加攻击力的牌,根据这样求出每一个枚举的个数的最大攻击值,并且更新答案最大值即可。
【代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=1005;
int num;
struct Node
{
int a,b;
}node[maxn];
bool cmp(Node a,Node b)
{
return a.a-num*a.b>b.a-num*b.b;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&node[i].a,&node[i].b);
LL ans=0;
for(int i=1;i<=n;i++)
{
num=i;
LL t=0;
sort(node+1,node+n+1,cmp);
for(int j=1;j<=i;j++)t+=node[j].a;
for(int j=i+1;j<=n;j++)t+=i*node[j].b;
ans=max(ans,t);
}
printf("%lld\n",ans);
}