Codeforces Round #633 (Div. 2)
A. Filling Diamonds
求菱形摆放填充图形的方案数。
Solution
当一个竖着摆放的菱形确定后,其他位置都被确定了,看图中共几个可以竖着填充菱形的位置。
答案即为n。
代码
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
typedef unsigned long long ll;
ll n;
int main()
{
int T;
scanf("%d",&T);
while(T -- )
{
scanf("%lld",&n);
printf("%lld\n",n);
}
return 0;
}
B. Sorted Adjacent Differences
把给定的n个数字的序列a1,a2,…an 重新排列。
使得新序列满足 |a1 − a2|≤|a2 − a3|≤…≤|an−1 − an|
Solution
因为要让差值越大的越靠后,所以每次取当前的最大最小放在序列的最后,即先取最大作为an,最小作为an-1,然后次大an-2,次小an-3,依次下去。
特别的要考虑奇数个的情况,最后剩的一个放到a1即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int SZ = 1e5 + 10;
int num[SZ],ans[SZ];
int main()
{
int T;
scanf("%d",&T);
while(T -- )
{
int n;
scanf("%d",&n);
for(int i = 1;i <= n;i ++ )
{
scanf("%d",&num[i]);
}
int temp = n;
sort(num + 1,num + n + 1);
for(int i = 1;i <= n/2;i ++ )
{
ans[temp --] = num[i];
ans[temp --] = num[n - i + 1];
}
if(n % 2 == 1) ans[temp] =num[n/2 + 1];
for(int i = 1;i <= n;i ++ )
printf("%d ",ans[i]);
printf("\n");
}
return 0;
}
C. Powered Addition
第i秒可以给任意l到r区间里的数字(也可不选)都加上2^(i-1),问最少几次可以使得该序列非降。
Solution
每个位置只要改成大于等于前面的最大值即可,把差值做一个前缀和即可。记录每个位置需要加上的数字大小。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int SZ = 1e5 + 10;
const int INF = 0x3f3f3f3f;
int n;
ll num[SZ];
ll sum[SZ];
int main()
{
int T;
scanf("%d",&T);
while(T -- )
{
scanf("%d",&n);
for(int i = 1;i <= n;i ++ )
scanf("%lld",&num[i]);
memset(sum,0,sizeof(sum));
for(int i = 2;i <= n;i ++ )
{
if(sum[i - 1] > 0) sum[i] += sum[i - 1] + num[i - 1] - num[i];
else sum[i] += num[i - 1] - num[i];
}
ll maxn = sum[2];
for(int i = 3;i <= n;i ++ )
maxn = max(sum[i],maxn);
ll temp = 1,cnt = 0,tsum = 0;
while(tsum < maxn)
{
cnt ++;
tsum += temp;
temp *= 2;
}
printf("%lld\n",cnt);
}
return 0;
}
D. Edge Weight Assignment
给一个n个节点 n - 1条边的图,然后给n - 1条边附上一个权值,使得任意两个叶子之间的路径的每一条边异或和为0.
求使用不同权值的最小数量和最大数量。
Solution
首先考虑最小数量:
偶数个1异或起来为0,那么如果所有叶子节点两两之间都是偶数条边,那么可以把所有边都赋值为1,最小数量也就是1。
如果存在两个叶子节点之间是奇数条边,那么全填1显然不行,我们考虑一种方案,取三条边填三个数异或起来为0(例如3,2,1),剩下的边数则为偶数条,全填1即可。故最小数量为3.
判断奇数偶数条边的具体操作方法就是任取一个叶子开始染色(黑白),然后判断是否叶子既有黑又有白。
再考虑最大数量:
根据样例我们可知,一个点与他的所有叶子节点的边是一样的,也就是说它的x个叶子节点都是一样的,可以等价为只有一个,不影响权值数量的使用。所以我们先把所有的等价叶子节点缩为一个,整张图就会变成多条链相交的样子。如同样例三。
再由样例提示,变成这样的链图后,所有边都可以填一个不同的值。最大数量也就是剩下的所有边数。答案也就是剩下的点数减一。
代码
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int SZ = 1e6 + 5;
struct edge
{
int v,nxt;
}line[SZ];
int fist[SZ],in[SZ],leaf[SZ],color[SZ];
int temp,n;
inline void build(int x,int y)
{
line[++temp] = (edge){y,fist[x]};
fist[x] = temp;
}
inline void dfs(int u,int col)
{
color[u] = col;
for(int i = fist[u];i != -1;i = line[i].nxt)
{
if(color[line[i].v]) continue;
dfs(line[i].v,3 - col);
}
}
int main()
{
int x,y;
memset(fist,-1,sizeof(fist));
scanf("%d",&n);
for(int i = 1;i < n;i ++ )
{
scanf("%d%d",&x,&y);
build(x,y);
build(y,x);
in[x] ++;
in[y] ++;
}
for(int i = 1;i <= n;i ++ )
{
if(in[i] == 1)
leaf[line[fist[i]].v] ++ ;
}
int minn = 1,maxn = n - 1;
for(int i = 1;i <= n;i ++ )
maxn -= max(0,leaf[i] - 1);
dfs(1,1);
int now = 0;
for(int i = 1;i <= n;i ++ )
{
if(in[i] == 1)
{
if(color[i] == 1) now |= 1;
else now |= 2;
}
}
if(now == 3) minn = 3;
printf("%d %d\n",minn,maxn);
return 0;
}
2020.4.14