Codeforces Round 608 Div2
作者:互联网
A
题意
水题
思路
水题
代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a,b,c,d,e,f,res=0;
scanf("%d%d%d%d%d%d",&a,&b,&c,&d,&e,&f);
if(e>f)
{
res+=min(a,d)*e;
d-=min(a,d);
res+=min(min(b,c),d)*f;
}
else
{
res+=min(min(b,c),d)*f;
d-=min(min(b,c),d);
res+=min(a,d)*e;
}
printf("%d\n",res);
}
B
题意
给一个序列,由W,B组成,代表白色和黑色。每次操作可以选择两个相邻的位置,然后把它们的颜色取反(不是交换),可以操作任意次。找出能否使得序列变全黑或全白的操作。
思路
按目标全黑或全白扫一遍即可
代码
#include<bits/stdc++.h>
using namespace std;
const int MAX=205;
char input[MAX],s[MAX];
vector<int>v;
map<char,char>mp;
int main()
{
mp['W']='B';
mp['B']='W';
int n;
scanf("%d%s",&n,input);
strcpy(s,input);
int tot=0;
for(int i=0; i<n-1; i++)
if(s[i]=='W')
{
s[i]='B';
s[i+1]=mp[s[i+1]];
tot++;
v.push_back(i+1);
}
if(s[n-1]=='B')
{
printf("%d\n",tot);
for(int i=0; i<v.size(); i++)
printf("%d ",v[i]);
printf("\n");
return 0;
}
tot=0;
v.clear();
strcpy(s,input);
for(int i=0; i<n-1; i++)
if(s[i]=='B')
{
s[i]='W';
s[i+1]=mp[s[i+1]];
tot++;
v.push_back(i+1);
}
if(s[n-1]=='W')
{
printf("%d\n",tot);
for(int i=0;i<v.size();i++)
printf("%d ",v[i]);
printf("\n");
return 0;
}
printf("-1\n");
}
C
题意
有一个学校,坐标x,y。有若干学生,家在不同的地方,上学走和学校构成矩形内的任意曼哈顿路径,求某一点坐标,使得上学路上可以经过该点的学生最多。
思路
显然可以分为四个象限和四个坐标轴。分别计算一下上面的学生人数。然后取最大值。结果就是最大的那个区域的坐标轴离学校远一格。
代码
#include<bits/stdc++.h>
using namespace std;
int quadrant[5],axes[5];
int main()
{
int n,sx,sy,x,y;
scanf("%d%d%d",&n,&sx,&sy);
while(n--)
{
scanf("%d%d",&x,&y);
if(x==sx)
{
if(y>sy)
axes[2]++;
else
axes[4]++;
}
if(y==sy)
{
if(x>sx)
axes[1]++;
else
axes[3]++;
}
if(x>sx&&y>sy)
quadrant[1]++;
if(x<sx&&y>sy)
quadrant[2]++;
if(x<sx&&y<sy)
quadrant[3]++;
if(x>sx&&y<sy)
quadrant[4]++;
}
int maxx=-1;
for(int i=1; i<=4; i++)
{
int cur=axes[i]+quadrant[i]+quadrant[i==1?4:i-1];
if(maxx<cur)
{
maxx=cur;
if(i==1)x=sx+1,y=sy;
if(i==2)x=sx,y=sy+1;
if(i==3)x=sx-1,y=sy;
if(i==4)x=sx,y=sy-1;
}
}
printf("%d\n%d %d\n",maxx,x,y);
}
D
题意
有n个城堡,你带兵从1-n按顺序攻打。初始有k个士兵,攻打i号城堡需要ai个士兵(只是需要,不会有伤亡)。打完以后可以征兵,i号城堡可以征兵bi个,城堡攻打下来以后可以驻守,驻守需要1个士兵。驻守i号城堡可以得分ci分。此外还有一些秘密通道,u-v,代表可以从u号城堡派一个士兵去驻守v号城堡(保证u>v)。求能否攻打下全部的城堡,若能,则输出最大得分,否则输出-1。
思路
首先由于必须全部攻打下来才有得分,所以很容易想到一些贪心的结论:
- 征兵一定优于不征兵
- 如果当前城堡可以后面再驻守,那后面再驻守一定优于当前就驻守,并且越后驻守越好、
这样决策就只剩下:
- 当前城堡不能后面再驻守,决策要不要在这里驻守
- 当前城堡有秘密通道,决策要不要派兵回去驻守。
很明显是动态规划的问题。然后从数据范围很容易想到dp[i][j]表示到第i个城堡时有j个士兵时能获得的最大收益。转移就dp[i][j]由dp[i-1][j-bi]转移得到。然后再由dp[i][j]向dp[i][j-1]转移,取决于当前城堡有没有秘密通道。
代码
#include<bits/stdc++.h>
using namespace std;
const int MAX=5005;
int a[MAX],b[MAX],c[MAX],dp[MAX][MAX],pre[MAX];
vector<int>out[MAX],in[MAX],cur;
int main()
{
int n,m,k,u,v;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&a[i],&b[i],&c[i]),pre[i]=pre[i-1]+b[i];
while(m--)
{
scanf("%d%d",&u,&v);
in[v].push_back(u);
}
for(int i=1;i<=n;i++)
{
if(!in[i].size())continue;
sort(in[i].begin(),in[i].end());
out[in[i].back()].push_back(i);
}
memset(dp,-1,sizeof dp);
dp[0][k]=0;
for(int i=1;i<=n;i++)
{
for(int j=a[i]+b[i];j<=pre[i]+k;j++)
{
dp[i][j]=dp[i-1][j-b[i]];
if(dp[i][j]==-1)continue;
if(!in[i].size()&&j>=1)
dp[i][j-1]=max(dp[i][j-1],dp[i][j]+c[i]);
if(out[i].size())
{
cur.clear();
int sum=0;
for(int l=0;l<out[i].size();l++)
cur.push_back(c[out[i][l]]);
sort(cur.begin(),cur.end(),greater<int>());
for(int l=0;l<cur.size();l++)
{
sum+=cur[l];
if(j-l-1>=0)
dp[i][j-l-1]=max(dp[i][j-l-1],dp[i][j]+sum);
if(j-l-2>=0&&!in[i].size())
dp[i][j-l-2]=max(dp[i][j-l-2],dp[i][j]+sum+c[i]);
}
}
}
}
int res=-1;
for(int i=0;i<=pre[n]+k;i++)
res=max(res,dp[n][i]);
printf("%d\n",res);
}
E
题意
定义一个函数f:
\[
\begin{eqnarray}
f(x)=\begin{cases}
\frac x2 &x为偶数\\
x-1 &x为奇数
\end{cases}
\end{eqnarray}
\]
对于一个数x连续调用f(x),得到一个序列。如对15得到15,14,7,6,3,2,1。现在给出n,k,求一个数x,使得x在1-n中各数的序列中,至少有k个序列包含x。
思路
很容易想到答案具有单调性。但是通过样例可以发现不是单纯的单调性,要分奇偶。奇数答案和偶数答案内部都具有单调性。所以分奇偶二分答案,复杂度也是可行的。所以问题转化为判断一个数x,在给定的序列中到底出现几次。把序列画成一棵树可以找到规律。
如图可得规律,x的出现次数就是以x为根节点的子树的节点个数(最大值要限制在n之内)。由规律可以log(n)的找出x的出现次数。总复杂度log^2(n)。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k;
ll check(ll x)
{
ll a,b,ans=0;
if(x&1ll)
a=b=x;
else
a=x,b=x+1;
while(a<=n)
{
ans+=min(n,b)-a+1;
a=a*2;
b=b*2+1;
}
return ans;
}
int main()
{
scanf("%I64d%I64d",&n,&k);
ll L=1,R=n/2+(n&1),res=-1;
while(L<=R)
{
ll mid=(L+R)>>1;
if(check(mid*2-1)>=k)
{
L=mid+1;
res=max(res,mid*2-1);
}
else
R=mid-1;
}
L=1,R=n/2;
while(L<=R)
{
ll mid=(L+R)>>1;
if(check(mid<<1)>=k)
{
L=mid+1;
res=max(res,mid<<1);
}
else
R=mid-1;
}
printf("%I64d\n",res);
}
标签:min,int,MAX,d%,608,Codeforces,res,Div2,dp 来源: https://www.cnblogs.com/cryingrain/p/12405403.html