题目链接:http://codeforces.com/contest/1037
目录
A. Packets
题目
拥有n个价值为1的硬币,要把它们分到若干个袋子里。要求使用若干个袋子的硬币和能凑出1-n的每个数,求要分的最小袋子数。举个例子,n=6,那么每个袋子里的硬币数分别为1,2,3;如果要凑4,就用1和3;要凑5,就用2和3;要凑6,就把它们全用了。
题解
通过观察得到,如果有了1和2,那么就不需要3,因为它能被凑出来,但是需要4,因为它不能被凑出来。依此类推,有了4,就不需要5,6,7了,下一个需要的数字就是8。很容易看出来,我们的最优选法一定是1,2,4,8,16……这类。
于是,给出一个n。答案就是log2(n)+1。因为1,2,4,8……求和的结果是 ,所以最终结果要+1。
代码
#include <bits/stdc++.h>
using namespace std;
#define INIT(x) memset(x,0,sizeof(x))
#define eps 1e-8
#define next next_
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x7fffffff;
const int inf = 0x3f3f3f3f;
const int maxn = 200005;
const int N = 105;
inline void read(int &x) {
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
inline void print(int x) {
if(x<0){ putchar('-'); x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
inline void caltime(int tt) {
tt = clock() - tt;
cerr << (double)tt/CLOCKS_PER_SEC << " seconds!" << endl;
}
inline void print_matrix(int a[N][N],int n,int m,bool flag=0) {
if(flag) {
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++)
cout<<a[i][j]<<" ";
cout<<endl;
}
}else {
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++)
cout<<a[i][j]<<" ";
cout<<endl;
}
}
}
inline void print_line(int *a,int n,bool flag=0) {
if(flag) {
for(int i=1;i<=n;i++)
cout<<a[i]<<" ";
}else {
for(int i=0;i<n;i++)
cout<<a[i]<<" ";
}
cout<<endl;
}
ll n,sum[maxn],ans;
int main()
{
cin>>n;
ans = log2(n);
ans++;
cout<<ans;
return 0;
}
B. Reach Median
题目
给出一个n(n为奇数)和s,然后输入n个数,现在可以将任意一个数+1或-1若干次。要求最小的操作次数,使得操作完后的数组经过排序后,其中位数恰好为s。
题解
贪心(不会证)。
首先将数组排序,然后将中位数和s比大小。如果比s大的话,那么就减小到s那么大,然后从当前位置向前遍历,遇到比它大的数都将它们变的和s一样大,然后统计出操作次数;如果比s小的情况同理。
代码
#include <bits/stdc++.h>
using namespace std;
#define INIT(x) memset(x,0,sizeof(x))
#define eps 1e-8
#define next next_
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x7fffffff;
const int inf = 0x3f3f3f3f;
const int maxn = 200005;
const int N = 105;
inline void read(int &x) {
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
inline void print(int x) {
if(x<0){ putchar('-'); x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
inline void caltime(int tt) {
tt = clock() - tt;
cerr << (double)tt/CLOCKS_PER_SEC << " seconds!" << endl;
}
inline void print_matrix(int a[N][N],int n,int m,bool flag=0) {
if(flag) {
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++)
cout<<a[i][j]<<" ";
cout<<endl;
}
}else {
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++)
cout<<a[i][j]<<" ";
cout<<endl;
}
}
}
inline void print_line(int *a,int n,bool flag=0) {
if(flag) {
for(int i=1;i<=n;i++)
cout<<a[i]<<" ";
}else {
for(int i=0;i<n;i++)
cout<<a[i]<<" ";
}
cout<<endl;
}
int n,s,a[maxn];
int main()
{
cin>>n>>s;
for(int i=0;i<n;i++)
read(a[i]);
sort(a,a+n);
ll ans = 0;
int temp = a[n/2];
if(s>temp) {
ans += s-temp;
for(int i=n/2+1;i<n;i++) {
if(a[i]<s) {
ans += s-a[i];
}else {
break;
}
}
}else if(s<temp){
ans += temp-s;
for(int i=n/2-1;i>=0;i--) {
if(a[i]>s) {
ans += a[i]-s;
}else {
break;
}
}
}
cout<<ans<<endl;
return 0;
}
C. Equalize
题目
有两个01字符串a和b,现在可以对字符串a进行以下两种操作:
(1)将位置i和位置j互换,这样的花费为 |j-i| ;
(2)将位置i改变。 (即0变成1,1变成0)
问如果要让a和b相等,需要的最小代价是多少。
题解
首先我们来看操作1,如果把任何两个距离大于1的位置互换,那么代价一定大于1,也就是不小于操作2的代价。
于是,我们只对距离为1的进行操作1,其余均进行操作2,然后就剩下一些代码细节了。
代码
#include <bits/stdc++.h>
using namespace std;
#define INIT(x) memset(x,0,sizeof(x))
#define eps 1e-8
#define next next_
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x7fffffff;
const int inf = 0x3f3f3f3f;
const int maxn = 200005;
const int N = 105;
inline void read(int &x) {
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
inline void print(int x) {
if(x<0){ putchar('-'); x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
inline void caltime(int tt) {
tt = clock() - tt;
cerr << (double)tt/CLOCKS_PER_SEC << " seconds!" << endl;
}
inline void print_matrix(int a[N][N],int n,int m,bool flag=0) {
if(flag) {
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++)
cout<<a[i][j]<<" ";
cout<<endl;
}
}else {
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++)
cout<<a[i][j]<<" ";
cout<<endl;
}
}
}
inline void print_line(int *a,int n,bool flag=0) {
if(flag) {
for(int i=1;i<=n;i++)
cout<<a[i]<<" ";
}else {
for(int i=0;i<n;i++)
cout<<a[i]<<" ";
}
cout<<endl;
}
int n;
string a,b;
int main()
{
cin>>n>>a>>b;
int res = 0;
for(int i=0;i<n;) {
if(a[i]!=b[i]) {
res++;
if(i<n-1&&a[i+1]!=a[i]&&a[i+1]!=b[i+1]) {
i++;
}
}
i++;
}
cout<<res<<endl;
return 0;
}
D. Valid BFS
题目
给一棵树,然后再给一个序列。问该序列是否是这棵树合法的BFS序。
题解
由于给定的bfs序对于同一父节点,其子节点的遍历顺序是无序的,但是大的顺序不会改变。
所以可以根据给定的顺序来对每一个父节点排序,这样能保证子节点的顺序和给出的顺序一致。
最后进行BFS,看与给定序列是否相同即可。
代码
#include <bits/stdc++.h>
using namespace std;
#define INIT(x) memset(x,0,sizeof(x))
#define eps 1e-8
#define next next_
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x7fffffff;
const int inf = 0x3f3f3f3f;
const int maxn = 200005;
const int N = 105;
inline void read(int &x) {
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
inline void print(int x) {
if(x<0){ putchar('-'); x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
inline void caltime(int tt) {
tt = clock() - tt;
cerr << (double)tt/CLOCKS_PER_SEC << " seconds!" << endl;
}
inline void print_matrix(int a[N][N],int n,int m,bool flag=0) {
if(flag) {
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++)
cout<<a[i][j]<<" ";
cout<<endl;
}
}else {
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++)
cout<<a[i][j]<<" ";
cout<<endl;
}
}
}
inline void print_line(int *a,int n,bool flag=0) {
if(flag) {
for(int i=1;i<=n;i++)
cout<<a[i]<<" ";
}else {
for(int i=0;i<n;i++)
cout<<a[i]<<" ";
}
cout<<endl;
}
int n,a[maxn];
int reorder[maxn];
bool vis[maxn];
vector<int> e[maxn];
vector<int> s;
int height = -1;
bool cmp(int a,int b) {
return reorder[a]<reorder[b];
}
void bfs() {
queue<int> q;
q.push(1);
while(!q.empty()) {
int res = q.front();
q.pop();
s.push_back(res);
vis[res] = 1;
for(int i=0;i<e[res].size();i++) {
if(!vis[e[res][i]])
q.push(e[res][i]);
}
}
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n-1;i++) {
int x,y;
read(x),read(y);
e[x].push_back(y); //不能保证一定是由父亲指向儿子,所以添加两次
e[y].push_back(x);
}
for(int i=0;i<n;i++) {
read(a[i]);
reorder[a[i]] = i;
}
// print_line(reorder,n);
for(int i=1;i<=n;i++) {
sort(e[i].begin(),e[i].end(),cmp);
}
bfs();
bool flag = 1;
for(int i=0;i<n;i++) {
if(s[i]!=a[i]) {
flag = 0;
break;
}
}
if(flag) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
return 0;
}