noip40
T1
记当前位置 \(i\) 上的颜色,上次出现的位置为 \(last_{1}\) ,上上次出现的位置为 \(last_{2}\) ,则,把当前点的颜色加进来,并且让其产生贡献的话,则会对 \([last_{2}+1,last_{1}]\) ,造成 \(-val_{i}\) 的贡献,对 \([last_{1}+1,i]\) 造成 \(val_{i}\) 的贡献。
发现就是个区间加,用线段树维护,每次加入新颜色后的最大值就是 \(1\) 号节点所存储的信息。
Code
#include<cstdio>
#define MAX 1000010
#define re register
#define int64_t long long
namespace OMA
{
int n,m,c[MAX],d[MAX],last[MAX][2];
template<typename type>inline type max(type a,type b)
{ return a>b?a:b; }
struct Segment_Tree
{
struct TREE
{
//int l,r;
int64_t xam;
int64_t lazy;
}st[MAX<<2];
#define ls(p) p<<1
#define rs(p) p<<1|1
#define mid(p) (lp+rp>>1)
inline void Push_up(int p)
{ st[p].xam = max(st[ls(p)].xam,st[rs(p)].xam); }
inline void Push_down(int p)
{
if(st[p].lazy)
{
st[ls(p)].xam += st[p].lazy;
st[rs(p)].xam += st[p].lazy;
st[ls(p)].lazy += st[p].lazy;
st[rs(p)].lazy += st[p].lazy;
st[p].lazy = 0;
}
}
/*inline void build(int p,int l,int r)
{
st[p].l = l,st[p].r = r;
if(l==r)
{ return ; }
build(ls(p),l,mid(p)),build(rs(p),mid(p)+1,r);
}*/
inline void update(int p,int l,int r,int val,int lp,int rp)
{
if(l<=lp&&rp<=r)
{ st[p].xam += val,st[p].lazy += val; return ; }
Push_down(p);
if(l<=mid(p))
{ update(ls(p),l,r,val,lp,mid(p)); }
if(r>mid(p))
{ update(rs(p),l,r,val,mid(p)+1,rp); }
Push_up(p);
}
}Tree;
struct stream
{
template<typename type>inline stream &operator >>(type &s)
{
int w=1; s=0; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
return s*=w,*this;
}
}cin;
signed main()
{
cin >> n >> m;
for(re int i=1; i<=n; i++)
{ cin >> c[i]; }
for(re int i=1; i<=m; i++)
{ cin >> d[i]; }
//Tree.build(1,1,n);
int64_t ans = 0;
for(re int i=1; i<=n; i++)
{
if(last[c[i]][0])
{
Tree.update(1,last[c[i]][0]+1,last[c[i]][1],-d[c[i]],1,n);
Tree.update(1,last[c[i]][1]+1,i,d[c[i]],1,n);
}
else if(last[c[i]][1])
{
Tree.update(1,1,last[c[i]][1],-d[c[i]],1,n);
Tree.update(1,last[c[i]][1]+1,i,d[c[i]],1,n);
}
else
{ Tree.update(1,1,i,d[c[i]],1,n); }
last[c[i]][0] = last[c[i]][1];
last[c[i]][1] = i;
//printf("max now := %lld\n",Tree.st[1].xam);
ans = max(ans,Tree.st[1].xam);
}
printf("%lld\n",ans);
return 0;
}
}
signed main()
{ return OMA::main(); }
T2
发现最优的且非0的距离,肯定是一个点经过了一个跟它距离为0的点,到达了另一个点。
考虑将坐标系旋转45度,则原先点的坐标变成了 \((\frac{\sqrt{2}(x-y)}{2},\frac{\sqrt{2}(x+y)}{2})\) ,为了方便,直接在此乘上一个 \(\sqrt{2}\) ,这样算答案时就不用再乘了,坐标转换在读入时就可以完成。
转换完坐标后,此题答案就是 \(\min((x-y),(x+y))\) 。
考虑按 \(x\) 排序,将 \(x\) 相等的放进一个集合中,表示这些点之间的距离为 \(0\) 。
再按 \(y\) 排序,同样将 \(y\) 相等的放进一个集合。
上面两步可以用并查集实现。
找最小值,就再按 \(x\) 排一遍序,找第一个跟它u不在一个集合内的更新答案,并将满足最小答案的都记下来,同样的,按 \(y\) 再做一边。
最后统计对数,就是合法的集合的大小相乘即可,记得去重。
Code
#include<vector>
#include<cstdio>
#include<algorithm>
#define MAX 100010
#define re register
#define INF 2147483647
using std::sort;
using std::unique;
using std::vector;
using std::pair;
using std::make_pair;
namespace OMA
{
int n,cnt,ans=INF;
struct my
{ int x,y,id; }p[MAX];
vector<pair<int,int>>edge;
inline bool cmp1(const my &a,const my &b)
{ return a.x<b.x; }
inline bool cmp2(const my &a,const my &b)
{ return a.y<b.y; }
inline int abs(int a)
{ return a>=0?a:-a; }
inline int min(int a,int b)
{ return a<b?a:b; }
int fa[MAX],size[MAX];
inline int find(int x)
{ return x!=fa[x]?fa[x] = find(fa[x]):x; }
inline void merge(int x,int y)
{
int r1 = find(x),r2 = find(y);
if(r1!=r2)
{
fa[r1] = r2;
size[r2] += size[r1];
}
}
inline void solve()
{
for(re int i=1; i<=n-1; i++)
{
for(re int j=i+1,r1,r2; j<=n; j++)
{
if((r1 = find(fa[p[i].id])) != (r2 = find(fa[p[j].id])))
{
int now = min(abs(p[i].x-p[j].x),abs(p[i].y-p[j].y));
if(now<=ans)
{
if(now<ans)
{ edge.clear(); ans = now; }
edge.push_back(make_pair(r1,r2));
edge.push_back(make_pair(r2,r1));
}
break ;
}
}
}
}
struct stream
{
template<typename type>inline stream &operator >>(type &s)
{
int w=1; s=0; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
return s*=w,*this;
}
}cin;
signed main()
{
//freopen("node.in","r",stdin);
cin >> n;
for(re int i=1,x,y; i<=n; i++)
{
fa[i] = i,size[i] = 1;
cin >> x >> y; p[i] = (my){x-y,x+y,i};
}
sort(p+1,p+1+n,cmp1);
for(re int i=1; i<=n-1; i++)
{
if(p[i].x==p[i+1].x)
{ merge(p[i].id,p[i+1].id); }
}
sort(p+1,p+1+n,cmp2);
for(re int i=1; i<=n-1; i++)
{
if(p[i].y==p[i+1].y)
{ merge(p[i].id,p[i+1].id); }
}
sort(p+1,p+1+n,cmp1); solve();
sort(p+1,p+1+n,cmp2); solve();
if(ans==INF)
{ printf("-1\n"); }
else
{
sort(edge.begin(),edge.end());
edge.erase(unique(edge.begin(),edge.end()),edge.end());
for(re int i=0; i<edge.size(); i++)
{ cnt += size[edge[i].first]*size[edge[i].second]; }
printf("%d\n%d\n",ans,cnt/2);
}
return 0;
}
}
signed main()
{ return OMA::main(); }
T3
小心CE
int64_t bin[MAX]={1};

noip40的更多相关文章
- [XJOI]noip40 T2统计方案
统计方案 小B写了一个程序,随机生成了n个正整数,分别是a[1]..a[n],他取出了其中一些数,并把它们乘起来之后模p,得到了余数c.但是没过多久,小B就忘记他选了哪些数,他想把所有可能的取数方案都 ...
随机推荐
- 重学Docker
转了云方向,代码都少写了 1. 为什么出现Docker 以前开发项目有开发的环境.测试的环境.还有生产的环境,每经过一阶段就要迁移项目.不同的环境有不同的配置,可能导致不可预估的错误,运维要经常性的改 ...
- java基础---集合(2)
一. Set 集合 java.util.Set集合是Collection集合的子集合,与List集合平级.该集合中元素没有先后放入次序,且不允许重复. 存储的数据在底层数组中并非按照数组索引的顺序添加 ...
- [TJOI2007]书架 题解
文中给了你一些句子,以及让你任意插入某个位置以及查询某个位置的句子. 发现因为是句子很难搞,所以开个 map 离散一下成数字.然后在额外开一个 map 记录这个数字对应的句子. 然后你要写一种支持插入 ...
- NOIP 模拟赛 day5 T2 水 故事题解
题目描述 有一块矩形土地被划分成 \(\small n×m\) 个正方形小块.这些小块高低不平,每一小块都有自己的高度.水流可以由任意一块地流向周围四个方向的四块地中,但是不能直接流入对角相连的小块中 ...
- 小白都能理解的TCP三次握手四次挥手
前言 TCP在学习网络知识的时候是经常的被问到知识点,也是程序员必学的知识点,今天小杨用最直白的表述带大家来认识认识,喜欢的朋友记得点点关注哈. 何为TCP 上点官方的话:是一种面向连接(连接导向)的 ...
- poj 折半搜索
poj2549 Sumsets 题目链接: http://poj.org/problem?id=2549 题意:给你一个含有n(n<=1000)个数的数列,问这个数列中是否存在四个不同的数a,b ...
- 微信小程序云开发-云函数-创建云函数
一.检查云函数环境 检查云函数环境时候,鼠标右键点击查看当前环境.如果存在多个云开发环境,要确保云函数的当前环境要与app.js中evn的环境值一致. 如果不一致,则鼠标右键切换当前云开发环境.(如果 ...
- 【洛谷P5008 逛庭院】tarjan缩点+贪心
既然没有题解,那么我就来提供给一份. -- 首先我们看到数据范围.妈耶!数据这么大,一开始还想用个DP来做,但是看着就不行,那么根据这个数据范围,我们大致可以猜到这道题的算法是一个贪心,那么我们怎么贪 ...
- Vue--el-menu 的自动跳转功能与自己的click事件冲突
一\先看elementUI说明 项目实际 此时点击活导航时以 index 作为 path 进行路由跳转 那么此时不要onclik事件了 如果此时有在有click 就
- MySQL 到底是如何做到多版本并发的?
之前的文章简单的介绍了 MySQL 的事务隔离级别,它们分别是:读未提交.读已提交.可重复读.串行化.这篇文章我们就来探索一下 MySQL 事务隔离级别的底层原理. 本篇文章针对 InnoDB 存储引 ...