您的位置:首页 > 其它

Codeforce Educational Round 6

2016-01-22 09:33 309 查看
Codeforce Educational Round 6

A:答案就是max(abs(x1-x2),abs(y1-y2)).

B:打一张表就行了。

C:题意:将一个序列尽量分成多的线段,线段两两不相交且每一条线段中都有且仅有一对权值相同的数。

贪心即可,用map代替hash,每次找到2个就clear。

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <map>
using namespace std;
map <int,int>mp;
void build(int Now,int l,int r) {
if(l == r) return ;
int Mid = (l + r) >> 1;
build(Now << 1,l,Mid);
build(Now << 1 | 1,Mid + 1,r);
}
int n,a,x[300010],y[300010],Ans = 0;
int main() {
build(1,1,1000);
scanf("%d",&n);
int head = 1;
for(int i = 1;i <= n;i ++)
{
scanf("%d",&a);
mp[a] ++ ;
if(mp[a] >= 2) Ans ++,x[Ans] = head,y[Ans] = i,mp.clear(),head = i + 1;
}
if(Ans == 0) printf("-1");
else
{
cout<<Ans<<endl;
for(int i = 1;i <= Ans - 1;i ++) cout<<x[i]<<' '<<y[i]<<endl;
cout<<x[Ans]<<' '<<n<<endl;
}
return 0;
}


D:题意:给出两个序列,可以交换0-2个数使得两序列所有数之和的差的绝对值最小。

(序列长度小于等于2000)

交换0次就是原本的和之差。(o(n+m))

交换一次可以n*m枚举。(o(n*m))

我们这样考虑,设第一个序列选了和为x的两个数,第二个序列选了和为y的两个数,那么最终答案就是abs(s1- s2-2*x+2*y),为了使答案最小,2*y-2*x就要尽量接近s2-s2,所以当选了一个x之后,选使得s1-s2+2*y最接近2*x的两个数比较优,我们注意到这是有单调性的。那么我们n^2+m^2求出所有的组合,分别排序,拿一个队列单调扫一下就行了。

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <ctime>
#define Int long long
using namespace std;
struct node{Int val;int x;int y;
};node f[5000010],g[5000010];
Int A[2010],B[2010],Ans,s1 = 0,s2 = 0;
int x1,x2,x3,x4,n,m,tot,cnt;
bool comp(const node &x,const node &y) {return x.val < y.val;}
bool comp2(const node &x,const node &y) {return x.val == y.val;}
void work1() {
for(int i = 1;i <= n;i ++)
for(int j = 1;j <= m;j ++)
{
Int x = abs(s1 - s2 - 2ll * A[i] + 2ll * B[j]);
if(x < Ans)
{
Ans = x;
x1 = i;
x2 = j;
}
}
}
void work2() {
if(n < 2 || m < 2) return ;
for(int i = 1;i <= n;i ++)
for(int j = i + 1;j <= n;j ++)
{
f[ ++ tot].val = A[i] + A[j];
f[tot].x = i;
f[tot].y = j;
}
for(int i = 1;i <= m;i ++)
for(int j = i + 1;j <= m;j ++)
{
g[ ++ cnt].val = B[i] + B[j];
g[cnt].x = i;
g[cnt].y = j;
}
sort(f + 1,f + tot + 1,comp);
tot = unique(f + 1,f + tot + 1,comp2) - f - 1;
sort(g + 1,g + cnt + 1,comp);
cnt = unique(g + 1,g + cnt + 1,comp2) - g - 1;
int head = 1;
for(int i = 1;i <= tot;i ++)
{
Int x = (s1 - s2 + 2ll * g[head].val);
Int y = (s1 - s2 + 2ll * g[head + 1].val);
while(head < cnt && abs(y - 2ll * f[i].val) < abs(x - 2ll * f[i].val))
{
head ++;
x = (s1 - s2 + 2ll * g[head].val);
y = (s1 - s2 + 2ll * g[head + 1].val);
}
Int ret = abs(s1 - s2 - 2ll * f[i].val + 2ll * g[head].val);
if(ret < Ans)
{
Ans = ret;
x1 = f[i].x;
x3 = f[i].y;
x2 = g[head].x;
x4 = g[head].y;
}
}
}
int main() {
scanf("%d",&n);
for(int i = 1;i <= n;i ++)
cin>>A[i],s1 += A[i];
scanf("%d",&m);
for(int i = 1;i <= m;i ++)
cin>>B[i],s2 += B[i];
Ans = abs(s1 - s2);
work1();
work2();
if(x3 != 0) cout<<Ans<<endl<<2<<endl<<x1<<' '<<x2<<endl<<x3<<' '<<x4;
else if(x1 != 0) cout<<Ans<<endl<<1<<endl<<x1<<' '<<x2;
else cout<<Ans<<endl<<0;
return 0;
}


E:题意:一棵树,点上有颜色,每次覆盖子树颜色,或者询问子树颜色种数。(颜色种数小于60种。)

Claris大大说可以无视颜色搞好害怕….

我们想到60种颜色正好在longlong 范围内,所以我们在线段树中维护二进制数,每次更新用 | 运算维护就可以了。

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <ctime>
#define Int long long
using namespace std;
struct node{int to;int next;
};node bian[800010];
int in[400010],out[400010],first[400010],size = 0;
int F[1600010],tim = 0,c[400010],n,m,a,b,p,Ans,num[400010];
Int val[1600010];
void inser(int x,int y) {
size ++;
bian[size].to = y;
bian[size].next = first[x];
first[x] = size;
}
void dfs(int x,int Anc) {
in[x] = out[x] = ++ tim;num[tim] = x;
for(int u = first[x];u;u = bian[u].next)
if(bian[u].to != Anc)
{
dfs(bian[u].to,x);
out[x] = max(out[x],out[bian[u].to]);
}
}
void pushdown(int Now) {
F[Now << 1] = F[Now << 1 | 1] = F[Now];
val[Now << 1] = val[Now << 1 | 1] = (1ll << (F[Now] - 1));
F[Now] = 0;
return ;
}
void build(int Now,int l,int r) {
if(l == r)
{
val[Now] = (1ll << (c[num[l]] - 1));
return ;
}
int Mid = (l + r) >> 1;
build(Now << 1,l,Mid);
build(Now << 1 | 1,Mid + 1,r);
val[Now] = val[Now << 1] | val[Now << 1 | 1];
}
void modify(int Now,int l,int r,int x,int y,int z) {
if(l >= x && r <= y)
{
F[Now] = z;
val[Now] = (1ll << (z - 1));
return ;
}
if(F[Now] != 0) pushdown(Now);
int Mid = (l + r) >> 1;
if(x <= Mid) modify(Now << 1,l,Mid,x,y,z);
if(y > Mid) modify(Now << 1 | 1,Mid + 1,r,x,y,z);
val[Now] = val[Now << 1] | val[Now << 1 | 1];
}
Int Ask(int Now,int l,int r,int x,int y) {
if(l >= x && r <= y) return val[Now];
if(F[Now] != 0) pushdown(Now);
int Mid = (l + r) >> 1;
Int ret = 0;
if(x <= Mid) ret |= Ask(Now << 1,l,Mid,x,y);
if(y > Mid) ret |= Ask(Now << 1 | 1,Mid + 1,r,x,y);
val[Now] = val[Now << 1] | val[Now << 1 | 1];
return ret;
}
int main() {
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i ++) scanf("%d",&c[i]);
for(int i = 1;i < n;i ++)
{
scanf("%d%d",&a,&b);
inser(a,b);
inser(b,a);
}
dfs(1,1);
build(1,1,n);
for(int i = 1;i <= m;i ++)
{
scanf("%d",&p);
if(p == 1)
{
scanf("%d%d",&a,&b);
modify(1,1,n,in[a],out[a],b);
}
else
{
Ans = 0;
scanf("%d",&a);
Int w = Ask(1,1,n,in[a],out[a]);
while(w > 0)
{
if(w % 2 == 1) Ans ++;
w >>= 1;
}
printf("%d\n",Ans);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: