A. Vika and Her Friends
题意:有一个n*m大小的矩阵,vika在点(a,b),她的k个朋友在分别(xi,yi),所有人每分钟都可以上下左右走一格,每一分钟vika先走,她的朋友后走,不能不走,问vika能否躲过朋友。
Solution
结论题,只要有一个朋友和她的距离是奇数,那么她肯定会被追上。
void solve()
{
int n,m,k;cin>>n>>m>>k;
int a,b;cin>>a>>b;
//cout<<n<<" "<<m<<" "<<k<<"\n";
//cout<<a<<" "<<b<<"\n";
int flag=0;
for(int i=1;i<=k;i++)
{
int x,y;
cin>>x>>y;
if(flag==1)
{
continue;
}
if((abs(x-a)+abs(y-b))%2==0)
{
cout<<"NO\n";
flag=1;
}
}
if(flag==1)return;
cout<<"YES\n";
}
B. Vika and the Bridge
题意:vika给一个由n块木板组成的桥用k种颜色进行了涂刷,每一块木板都有对应的颜色,现在油漆还没有干,她现在想要走过桥但是最多只能改变一个木板的颜色,vika最少需要横跨几个木板走一步才能过桥。
Solution
预处理出只走每种颜色木板需要横跨的最大距离和第二大距离,只改变一个木板的颜色可以让最大距离除以2向下取整,然后遍历每种颜色取最小即可
int a[N]; //第i块木板的颜色
int b[N]; //第i种颜色的最大距离
int c[N]; //第i种颜色木板的上一个位置
int d[N]; //第i种颜色木板的第二大距离
void solve()
{
int n,k;cin>>n>>k;
for(int i=1;i<=k;i++)
{
b[i]=-1;
c[i]=-1;
d[i]=-1;
}
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(b[a[i]]==-1)
{
b[a[i]]=i-1;
c[a[i]]=i;
//d[a[i]]=i-1;
}
else
{
int len=i-c[a[i]]-1;
if(d[a[i]]==-1)
{
if(len>=b[a[i]])
{
d[a[i]]=b[a[i]];
b[a[i]]=len;
}else
{
d[a[i]]=len;
}
}else
{
if(len>=b[a[i]])
{
d[a[i]]=b[a[i]];
b[a[i]]=len;
}else if(len>=d[a[i]])
{
d[a[i]]=len;
}
}
c[a[i]]=i;
}
}
for(int i=1;i<=k;i++)
{
if(b[i]==-1)continue;
int len=n-c[i];
if(d[i]==-1)
{
if(len>=b[i])
{
d[i]=b[i];
b[i]=len;
}else
{
d[i]=len;
}
}else
{
if(len>=b[i])
{
d[i]=b[i];
b[i]=len;
}else if(len>=d[i])
{
d[i]=len;
}
}
}
int ans=INF;
for(int i=1;i<=k;i++)
{
if(b[i]==-1)continue;
ans=min(ans,max(d[i],b[i]/2));
//cout<<d[i]<<" "<<b[i]<<"\n";
//cout<<ans<<" ";
}
cout<<ans<<"\n";
}
C. Vika and Price Tags
题意:有两个数组a和b,每次操作可以生成一个新数组c,其中
\[c[i]=|a[i]-b[i]| \]在此之后令数组b改名变为a,数组c改名变为数组b,是否能进行若干次操作,使得a在某一个时刻变为全0
Solution
首先,如果a[i]=0并且b[i]=0,那么a[i]会一直为0,
其次,如果a[i]!=0并且b[i]!=0,那么最后a[i]和b[i]中间一定有一个在某一时刻会变为0
最后,如果a[i]和b[i]当中有一个是0,另一个不是0
假设a[i]=0,b[i]=x
那么最后它会以(0,x),(x,x),(x,0),(0,x)...循环下去
所以我们需要找到a[i]第一次为0的时刻,并且模三,如果所有a[i]为0的时刻在模三下是相同的,那么可以成立,反之不行。
假设a[i]比b[i]大(如果小那么就进行一次操作)
那么a[i]和b[i]会在若干次操作后变为a[i]%b[i]和b[i],操作次数取决于cnt=a[i]/b[i]的奇偶性,可以发现
如果是偶数,那么会依次进行1 2 1 2 1 2...1 2 1 2 1 2次操作
即(cnt-1)*3/2次操作
其中a[i]会变成b[i]
如果是奇数,那么会依次进行1 2 1 2 1 2...1 2 1 2 1次操作
即1+(cnt-1)*3/2次操作
其中b[i]会变成b[i]
之后用set统计即可
void solve()
{
int n;cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>b[i];
for(int i=1;i<=n;i++)
{
int x=a[i],y=b[i];
int res=0;
while(x!=0)
{
if(y==0)
{
res++;
break;
}
if(x<y)
{
int temp=abs(x-y);
x=y;
y=temp;
res++;
}
int cnt=x/y;
if(cnt&1)
{
int temp=x%y;
x=y;
y=temp;
res+=1+(cnt-1)*3/2;
}else
{
int temp=x%y;
x=temp;
res+=(cnt*3)/2;
}
}
c[i]=res;
}
set<int>st;
for(int i=1;i<=n;i++)
{
if(a[i]==0&&b[i]==0)continue;
st.insert(c[i]%3);
//cout<<c[i]<<" \n"[i==n];
}
cout<<((st.size()<=1)?"YES\n":"NO\n");
}
D. Vika and Bonuses
题意:最开始有一个数s,答案最开始是0,可以进行以下两种操作共计最多k次,
1.使答案加上s
2.使s加上s的个位的数
问最后答案最大是多少
Solution
易发现,如果一直进行操作2,个位上会出现2 4 8 6的循环,那么我们可以发现
\[ans=(s+20x)*(k-4x) \]这是一个抛物线,平分线为(5k-s)/40,直接把个位上是2 4 8 6的每种情况都算一遍,最后取最大值即可
注意如果个位上是5则最多进行一次操作2
并且个位上是奇数时需要先进行一次操作2然后再进行才能进入循环
//0
//1 2 4 8 6
//2 4 8 6
//3 6 2 4 8 6
//4 8 6 2 4 8 6
//5 0
//6 2 4 8 6
//7 4 8 6 2 4 8 6
//8 6 2 4 8 6
//9 8 6 2 4 8 6
int check(int s,int k)
{
int mid=(5*k-s)/40;
int x=min(mid,k/4);
int res=s*k;
if(x>0)res=max(res,(s+20*x)*(k-4*x));
x=min(x+1,k/4);
if(x>0)res=max(res,(s+20*x)*(k-4*x));
return res;
}
void solve()
{
int s,k;cin>>s>>k;
int ans=0;
int cnt=s%10;
if(cnt==5)
{
cout<<max(s*k,(s+5)*(k-1))<<"\n";
return;
}else if(cnt==0)
{
cout<<s*k<<"\n";
return;
}
ans=s*k;
if(cnt&1)
{
ans=max(ans,(s+cnt)*(k-1));
s+=cnt;k--;
}
for(int i=0;i<4;i++)
{
//cout<<s<<" "<<k<<" "<<check(s,k)<<"\n";
if(k>0)ans=max(ans,check(s,k));
s+=s%10;
k--;
}
cout<<ans<<"\n";
}
标签:木板,885,int,res,Codeforces,len,else,操作,Div
From: https://www.cnblogs.com/HikariFears/p/17560388.html