A. Be Positive
直接找数组中正数和负数的个数即可。
#include "bits/stdc++.h"
using namespace std;
int main()
{
int n;
cin>>n;
int a=0,b=0;
int x;
for (int i = 0; i < n; ++i) {
scanf("%d",&x);
if(x>0)a++;
else if(x<0)b++;
}
n=(n+1)/2;
if(a>=n)puts("1");
else if(b>=n)puts("-1");
else puts("0");
}
B. Two Cakes
每个数字出现两次,记录他们的下标,第一个人走下标小的,另外一个走下标大的,这样可以保证路程最短。
#include "bits/stdc++.h"
using namespace std;
int a[200004];
int b[200004];
int main()
{
int n;
scanf("%d",&n);
int x;
memset(a,0, sizeof(a));
memset(b,0, sizeof(b));
for (int i = 1; i <= 2*n; ++i) {
scanf("%d",&x);
if(a[x]==0)a[x]=i;
else {
b[x]=i;
if(a[x]>b[x])swap(a[x],b[x]);
}
}
long long ans=0;
a[0]=1,b[0]=1;
for (int i = 1; i <= n; ++i) {
ans+=abs(a[i]-a[i-1]);
ans+=abs(b[i]-b[i-1]);
}
printf("%lld\n",ans);
}
C. Connect
首先考虑最朴素的暴力做法,暴力枚举两个点建边然后跑bfs,复杂度o(n^6),显然不行。
因为水路不能走,所以预处理出从起点出发能到达的点,和从终点出发能到达的点,然后再枚举这两个集合中的点,可以剪掉一些情况,但是在极端情况下还是会T。
此时考虑两个集合点建边,长度最小的边一定是从这两个集合的边缘出发的,所以只需要维护两个集合的边缘的点即可,最坏情况复杂度O(n^4)。
#include "bits/stdc++.h"
using namespace std;
char mp[54][54];int n;int sx,sy,ex,ey;
int f[4][2]={0,1,1,0,0,-1,-1,0};
bool vis[54][54];
struct node
{
int x,y;
};
bool inmp(int x,int y)
{
return x>=1&&x<=n&&y>=1&&y<=n;
}
vector<node>st;//起点边缘集合
vector<node>ed;//终点边缘集合
void init()
{
queue<node>q;
q.push({sx,sy});
memset(vis,0, sizeof(vis));
while(!q.empty())
{
node t=q.front();q.pop();
int ok=0;
for (int i = 0; i < 4; ++i) {
node now=t;
now.x+=f[i][0];now.y+=f[i][1];
if(!inmp(now.x,now.y))continue;
if(vis[now.x][now.y])continue;
else if(mp[now.x][now.y]=='0'){
q.push(now);vis[now.x][now.y]=1;
}
else ok=1;//判断边缘
}
if(ok)st.push_back(t);
}
while(!q.empty())q.pop();
q.push({ex,ey});
memset(vis,0, sizeof(vis));
while(!q.empty())
{
node t=q.front();q.pop();
int ok=0;
for (int i = 0; i < 4; ++i) {
node now=t;
now.x+=f[i][0];now.y+=f[i][1];
if(!inmp(now.x,now.y))continue;
if(vis[now.x][now.y])continue;
else if(mp[now.x][now.y]=='0'){
q.push(now);vis[now.x][now.y]=1;
}
else ok=1;//判断边缘
}
if(ok)ed.push_back(t);
}
}
bool bfs(int x1,int y1,int x2,int y2)
{
queue<node>q;
memset(vis,0, sizeof(vis));
q.push({sx,sy});
while(!q.empty())
{
node t=q.front();q.pop();
if(t.x==x1&&t.y==y1)
{
t={x2,y2};
}
if(t.x==ex&&t.y==ey)return 1;
for (int i = 0; i < 4; ++i) {
node now = t;
now.x+=f[i][0];
now.y+=f[i][1];
if(!inmp(now.x,now.y))continue;
if(vis[now.x][now.y])continue;
if(mp[now.x][now.y]=='0'){
q.push(now);
vis[now.x][now.y]=1;
}
}
}
return 0;
}
int main()
{
scanf("%d",&n);
cin>>sx>>sy>>ex>>ey;
for (int i = 1; i <= n; ++i) {
scanf("%s",mp[i]+1);
}
int ans=1e9;
init();
for (int i = 0; i < st.size(); ++i) {
for (int j = 0; j < ed.size(); ++j) {
int xxx=(st[i].x-ed[j].x)*(st[i].x-ed[j].x)+(st[i].y-ed[j].y)*(st[i].y-ed[j].y);
if(ans<=xxx)continue;
if(bfs(st[i].x,st[i].y,ed[j].x,ed[j].y))
ans=xxx;
}
}
if(ans==1000000000)ans=0;
printf("%d\n",ans);
}
D1 D2. Toy Train
因为只能单向行驶,所以最终答案一定是所有点中所需时间的最大值。
考虑其中某一个点p,p点有a颗糖,要运输完p点的糖果,至少需要跑a-1个周期+最后一颗糖果所需要的时间
那么此时time=(a-1)*n+min(b),b为从p到按方向离p点最近的糖果的终点的点,那么预处理离p点最近的点和p点的糖果数量即可。复杂度O(n^2)。
#include "bits/stdc++.h"
using namespace std;
int Num[5004];//糖果数量
int mini[5004];//最近的点的坐标
int ans[5004];
int main()
{
int n,m;
cin>>n>>m;
int x,y;
memset(mini,0x3f3f3f3f, sizeof(mini));
memset(Num,0, sizeof(Num));
for (int i = 0; i < m; ++i) {
cin>>x>>y;
if(y<x)y+=n;//因为只能单向运输
Num[x]++;
mini[x]=min(mini[x],y);
}
for (int i = 1; i <= n; ++i) {//枚举起点
int sum=0;
for (int j = 0; j < n; ++j) {//枚举从该起点开始的所有点
int p=(i+j<=n?i+j:i+j-n);
int num=j;
if(Num[p]==0)continue;
num+=(Num[p]-1)*n;
num+=mini[p]-p;
sum=max(sum,num);
}
ans[i]=sum;
}
for (int i = 1; i <= n; ++i) {
printf("%d ",ans[i]);
}
puts("");
}
E. Wrong Answer
为了方便处理,设定n=2000。
将前1998个数全部置0,仅改变最后两个数。
设最后两个数为a,b且a为负数。即 0 0 0 0 0 0……a b
正确答案为 2000*(a+b),Alice的答案为b。
那么有
#include "bits/stdc++.h"
using namespace std;
int n,a[2004];
int main()
{
int k;
cin>>k;
int a,b;
b=1000000-k%2000;
a=(k+b)/2000-b;
printf("2000\n");
for (int i = 0; i < 1998; ++i) {
printf("0 ");
}
printf("%d %d\n",a,b);
}