Codeforces Round #592 (Div. 2)
A.B略
C.The Football Season
题意: 给你w,d,p,n,是否存在同时满足等式
#include
using namespace std;
typedef long long ll;
int main()
{
ll n,p,d,w;
scanf("%lld%lld%lld%lld",&n,&p,&w,&d);
if(w*n<p||p%__gcd(w,d))
{
puts("-1");
return 0;
}
else
{
if(p%w==0)
{
printf("%lld %lld %lld\n",p/w,0ll,n-p/w);
return 0;
}
for(int i=1;i<w;i++)
{
if((p-i*d)%w==0)
{
ll x=(p-i*d)/w;
if(x>=0&&x+i<=n)
{
printf("%lld %d %lld\n",x,i,n-x-i);
return 0;
}
}
}
}
puts("-1");
return 0;
}
D. Paint the Tree
题意: 给你一颗树,每个结点都有三个颜色点权,且相连的三个点不能有相同的颜色,问染整棵树的最小值为多少?
思路: 只有一条链的时候才存在方案,并且考虑在链上的话,前两个点的颜色确定了,那么整条链的颜色都确定了。所以暴力六种情况取其中最小即可
#include
using namespace std;
typedef long long ll;
const int N=1e5+5;
int a[N][4];
vector<int>G[N];
int vis[N];
int res[N];
ll ans;
ll tmp;
void dfs1(int u,int fa,int x,int y)
{
vis[u]=y;
tmp+=a[u][y];
for(auto v:G[u])
{
if(v==fa)
continue;
dfs1(v,u,y,6-x-y);
}
}
void dfs(int i,int j)
{
vis[i]=1;
tmp=a[i][1];
dfs1(j,i,1,2);
memcpy(res,vis,sizeof vis);
ans=tmp;
vis[i]=1;
tmp=a[i][1];
dfs1(j,i,1,3);
if(ans>tmp)
{
ans=tmp;
memcpy(res,vis,sizeof vis);
}
vis[i]=2;
tmp=a[i][2];
dfs1(j,i,2,1);
if(ans>tmp)
{
ans=tmp;
memcpy(res,vis,sizeof vis);
}
vis[i]=2;
tmp=a[i][2];
dfs1(j,i,2,3);
if(ans>tmp)
{
ans=tmp;
memcpy(res,vis,sizeof vis);
}
vis[i]=3;
tmp=a[i][3];
dfs1(j,i,3,1);
if(ans>tmp)
{
ans=tmp;
memcpy(res,vis,sizeof vis);
}
vis[i]=3;
tmp=a[i][3];
dfs1(j,i,3,2);
if(ans>tmp)
{
ans=tmp;
memcpy(res,vis,sizeof vis);
}
}
int main()
{
int n;
scanf("%d",&n);
for(int j=1;j<=3;j++){
for(int i=1;i<=n;i++){
scanf("%d",&a[i][j]);
}
}
for(int i=1;i<=n-1;i++)
{
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
int flag;
for(int i=1;i<=n;i++)
{
if(G[i].size()>2)
{
puts("-1");
return 0;
}
if(G[i].size()==1)
flag=i;
}
//cout<
dfs(flag,G[flag][0]);
printf("%lld\n",ans);
for(int i=1;i<=n;i++){
printf("%d ",res[i]);
}
puts("");
return 0;
}
E. Minimizing Difference
题意: 给你一个数组,每次操作可以使其中一个元素+1或-1,问最多有k次操作,使得数组中max-min最小
思路: 将数组排序后,同时从两个方向一个一个移动即可
#include
using namespace std;
typedef long long ll;
const int N=1e5+5;
int a[N];
int main()
{
int n;
ll k;
scanf("%d%lld",&n,&k);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+1+n);
for(int i=1;i<=n/2;i++)
{
ll cnt=1ll*(a[i+1]-a[i]+a[n-i+1]-a[n-i])*i;
if(k>=cnt){
k-=cnt;
}
else {
printf("%lld\n",1ll*(a[n-i+1]-a[i]-k/i));
return 0;
}
}
printf("0\n");
return 0;
}
F. Chips
题意: 给出一个环,每个点有黑白两色,然后有k操作,每次操作是这样的:
如果一个点两边的颜色有一个和自己相同,那么这个点的颜色不变,否则这个点的颜色翻转,黑变白,白变黑。
问k次操作后每个点的颜色。
思路: 我们可以得知当有两个相邻点颜色一样,则永远不会翻转,然后向两端扩展,每次+1最后可以得到每个点在第几次不会再翻,一种除外WBWBWB这种
注意向两端拓展着用跑两遍,我被这个卡了很久
#include
#include
#include
using namespace std;
char str[200010];
int tim[200010];
int main()
{
memset(tim,0x3f,sizeof(tim));
int n,k;scanf("%d %d",&n,&k);
scanf("%s",str);
for(int i=0;i<n;i++)
if(str[i]==str[(i+1)%n]||str[i]==str[(i-1+n)%n])
tim[i]=0;
for(int i=0;i<2*n;i++)
tim[i%n]=min(tim[i%n],tim[(i-1+n)%n]+1);
for(int i=2*n-1;i>=0;i--)
tim[i%n]=min(tim[i%n],tim[(i+1)%n]+1);
for(int i=0;i<n;i++)
if(min(tim[i],k)&1)
printf("%c",'W'+'B'-str[i]);
else printf("%c",str[i]);
printf("\n");
return 0;
}
/*
16 2
WBWBWBBBWBWBWBWB
*/
G. Running in Pairs
题意: 构造两个排列,使得 ∑ i = 1 n m a x ( p i , q i ) < = k \sum_{i=1}^{n}max(p_i,q_i)<=k ∑i=1nmax(pi,qi)<=k,且使得结果尽可能的大
思路: 首先我们确定一个排列为1……n,接着构造第二个排列,我们可以知道sum最小为两个排列一模一样(n+1)*n/2,
考虑第二个排列刚开始也是顺序排放的。
然后考虑交换位置视为元素左移和元素右移。
显然,元素右移不会对答案产生影响。
但是元素左移,左移几个位置它就产生多少贡献。
那么显然可以发现这个变化是连续的,直接贪心即可。
#include
using namespace std;
typedef long long ll;
const int N=1e6+5;
ll n,k;
int a[N];
int main()
{
scanf("%lld%lld",&n,&k);
ll sum=n*(n+1)/2;
if(k<sum)
{
puts("-1");
return 0;
}
k-=sum;
for(int i=1;i<=n;i++)
a[i]=i;
int tmp=n;
for(int i=1;i<=n&&i<tmp;i++)
{
int res=tmp-i;
if(res<=k)
{
sum+=res;
k-=res;
swap(a[i],a[tmp]);
tmp--;
}
}
printf("%lld\n",sum);
for(int i=1;i<=n;i++)
printf("%d ",i);
puts("");
for(int i=1;i<=n;i++)
printf("%d ",a[i]);
puts("");
return 0;
}