[Elite 2010 U S Open Competition]求过原点的三角形数目、极角排序、维护

【题目大意】
给定N个二维平面上的点。
问他们取3个出来,过原点的三角形有多少个。
【算法分析】
先极角排序。
然后维护一个最长区间,使得区间中任意一个点对满足向量(O, i)和向量(O, j)的夹角【其它】
APIO最后一题的本质模型。
【CODE】
/*
ID:jie22221
TASK:tricount
LANG:C++
*/

#include #include #include #include using namespace std;
typedef long long lld;
const int N=100005;
int n;
struct Point{int x,y;}a[N];

void input(){
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d%d",&a[i].x,&a[i].y);
}

int get_xx(Point p){
if (p.x>=0 && p.y>0) return 1;
if (p.x>0 && p.y<=0) return 2;
if (p.x<=0 && p.y<0) return 3;
return 4;
}

int cj(Point p0,Point p1,Point p2){
lld res=(lld)(p1.x-p0.x)*(lld)(p2.y-p0.y)-(lld)(p1.y-p0.y)*(lld)(p2.x-p0.x);
if (res<0) return -1;
if (res==0) return 0;
return 1;
}

int cmp(const void *X,const void *Y){
Point x=*((Point*)X),y=*((Point*)Y);
int xx1=get_xx(x),xx2=get_xx(y);
if (xx1!=xx2) return xx1-xx2;
return cj(a[0],x,y);
}

void solve(){
lld ans=(lld)(n)*(n-1)*(n-2)/6,total;
int i,j=1;
for (i=1;i<=n;i++){
if (i==j) j=j%n+1;
while (i!=j%n+1 && cj(a[0],a[i],a[j%n+1])<0) j=j%n+1;
if (j else total=j-i;
ans-=total*(total-1)/2;
}
cout << ans << endl;
}

int main(){
freopen("tricount.in","r",stdin);
freopen("tricount.out","w",stdout);
input();
qsort(a+1,n,sizeof(Point),cmp);
solve();
}

[USACO Elite 2010 U S Open Competition GOLD slide]拓扑排序、动态规划

【题目地址】http://ace.delos.com/ioigate
【题目大意】
有中文的。。。略了。
【算法分析】
题目给出一个信息:无环。
于是topsort。
然后逆拓扑序dp回来。
F[i,j]表示到达第i个点,已经失控j次,所能得到的最坏积分。
然后转移的话,程序里有,很简短,就不写了。
【CODE】
/*
ID:jie22221
TASK:slide
LANG:C++
*/
#include #include #include #include using namespace std;
typedef long long lld;
const int N=50005;
const int E=150005;
const lld INF=(lld)(1)<<60;
struct gtp{int x,y,w,next;}g[E];
int n,m,L,e;
int ls[N],du[N],list[N];
lld F[N][11];

void input(){
scanf("%d %d %d",&n,&m,&L);
for (int i=1,x,y,w;i<=m;i++){
scanf("%d%d%d",&x,&y,&w);
g[++e].x=x; g[e].y=y; g[e].w=w; g[e].next=ls[x]; ls[x]=e;
du[y]++;
}
}

void bfs(){
int head=0,tail=0,i,t;
for (i=1;i<=n;i++)
if (!du[i]) list[++tail]=i;
while (head head++;
for (t=ls[list[head]];t;t=g[t].next){
du[g[t].y]–;
if (!du[g[t].y]) list[++tail]=g[t].y;
}
}
}

void dp(){
memset(F,200,sizeof(F));
F[n][0]=0;
int i,j,k,t;
lld Min,Max;
for (k=n;k>=1;k–){
i=list[k];
for (j=0;j<=L;j++){
Min=INF;
if (j){
for (t=ls[i];t;t=g[t].next)
if (F[g[t].y][j-1]>=0 && F[g[t].y][j-1]+g[t].w Min=F[g[t].y][j-1]+g[t].w;
}
Max=0;
for (t=ls[i];t;t=g[t].next)
Max=max(Max,F[g[t].y][j]+g[t].w);
F[i][j]=min(Max,Min);
}
}
cout << F[1][L] << 'n';
}

int main(){
freopen("slide.in","r",stdin);
freopen("slide.out","w",stdout);
input();
bfs();
dp();
}

[COCI 2009/2010 – Constest #7 RESTORAN]贪心骗分、未A、非完美算法

【题目地址】http://evaluator.hsin.hr/login.php?redirect=index.php
【题目大意】
一个N,E<=10^5的无向图
每条边可以染黑白两色。
求一个染色方案,使每一个度>1的点,都拥有与之相连的黑边和白边。
【算法分析】
。。。我只会骗分了,应该还可以写个随机调整搞一下。
我是把它当树来走,树边染上dep[p] mod 2+1的颜色。
然后其他边如果只有某一边需要,那么就完成那一边的需求。
否则随便完成某一边的需求。
【数据通过情况】
Test # Score Time Memory Result 1 0.0 0.00s 6956 kB You program printed 0, but there is a valid solution. 2 6.5 0.00s 6956 kB Correct! 3 6.5 0.00s 6956 kB Correct! 4 0.0 0.00s 6956 kB You program printed 0, but there is a valid solution. 5 0.0 0.00s 6956 kB Correct! 0.00s 6956 kB You program printed 0, but there is a valid solution. 0.00s 6956 kB You program printed 0, but there is a valid solution. 0.00s 6956 kB Correct! 0.00s 6956 kB You program printed 0, but there is a valid solution. 0.00s 6956 kB You program printed 0, but there is a valid solution. 0.00s 6956 kB Correct! 0.00s 6956 kB Correct! 6 0.0 0.11s 10000 kB Correct! 0.09s 6956 kB Correct! 0.00s 6956 kB You program printed 0, but there is a valid solution. 0.11s 10000 kB You program printed 0, but there is a valid solution. 0.10s 7916 kB You program printed 0, but there is a valid solution. 0.11s 8592 kB You program printed 0, but there is a valid solution. 0.11s 7720 kB Correct! 0.10s 8248 kB You program printed 0, but there is a valid solution.
显然。。。因为它搞到多组测试数据,完全没办法得很多分。。。但是过的点也不少了。。。
求正解
【CODE】
#include #include #include const int N=105555;
struct edge{int x,y,color,next,op;}g[N*2];
int n,e;
int ls[N],dep[N],du[N],donec[N],fa[N];

inline void addedge(int x,int y){
g[++e].x=x; g[e].y=y; g[e].next=ls[x]; ls[x]=e; g[e].op=e+1;
g[++e].x=y; g[e].y=x; g[e].next=ls[y]; ls[y]=e; g[e].op=e-1;
}

void init(){
int i,x,y,m;
scanf("%d%d",&n,&m);
for (i=1;i<=m;i++){
scanf("%d%d",&x,&y);
addedge(x,y);
du[x]++; du[y]++;
}
}

inline void draw(int t,int co){
if (g[t].color) return;
if (co==3 || co==1){
g[t].color=1;
g[g[t].op].color=1;
}
else{
g[t].color=2;
g[g[t].op].color=2;
}
if (!donec[g[t].x]) donec[g[t].x]=co;
if (donec[g[t].x]!=co) donec[g[t].x]=3;
if (!donec[g[t].y]) donec[g[t].y]=co;
if (donec[g[t].y]!=co) donec[g[t].y]=3;
}

void dfs(int p){
for (int t=ls[p];t;t=g[t].next)
if (!dep[g[t].y]){
dep[g[t].y]=dep[p]+1;
fa[g[t].y]=t;
draw(t,dep[p]%2+1);
dfs(g[t].y);
}
else if (g[t].op!=fa[p]){
if (donec[g[t].y]==3) draw(t,3-donec[p]);
else if (donec[g[t].y]==donec[p]) draw(t,3-donec[p]);
else draw(t,donec[p]);
}
}

void work(){
int i;
for (i=1;i<=n;i++)
if (!dep[i]){
dep[i]=1;
dfs(i);
}
}

void update(int p){
donec[p]=0;
for (int t=ls[p];t;t=g[t].next){
if (!donec[p]) donec[p]=g[t].color;
if (donec[p]!=g[t].color) {donec[p]=3; return;}
}
}

bool Try_opc(int ss){
for (int t=ls[g[ss].x];t;t=g[t].next)
if (g[t].color==g[ss].color && t!=ss){
g[ss].color=3-g[ss].color;
g[g[ss].op].color=g[ss].color;
donec[g[ss].x]=3;
update(g[ss].y);
return true;
}
return false;
}

void solve(){
bool flag=true;
for (int i=1;i<=n;i++)
for (int t=ls[i];t && du[i]>1 && donec[i]!=3;t=g[t].next)
if (Try_opc(t)) break;
for (int i=1;i<=n;i++)
if (du[i]>1 && donec[i]!=3){
flag=false;
}
if (!flag){
printf("0n");
return;
}
for (int i=1;i printf("%dn",g[i].color);
}

int main(){
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
init();
work();
solve();
}

[COCI 2009/2010 – Constest #7 KRALJEVI]矩阵上的各种维护 & 分类讨论

【题目地址】http://evaluator.hsin.hr/login.php?redirect=index.php
【题目大意】
在一个m*n的矩阵里,给出一些国际象棋中的王,让你求出所有王对(。。。就是那些点对)之间最小到达步数的和。
【算法分析】

LU[i][j]表示以(i,j)为右下角的这个矩形内的所有的王跳到(i,j)这个位置一共跳了多少步。
LS[i][j]表示以(i,j)为右下角的这个矩形内的所有的王的数目。
RU[i][j]和RS[i][j]同上。
UU[i][j]表示以从(1,j)到(i,j)这一路下来的王跳到(i,j)一共跳的步数。
US[i][j]表示以从(1,j)到(i,j)这一路下来一共有多少个王。

然后就是设法维护一下,像dp一样,并不是很难。
【CODE】
#include #include #include long long LU[1005][1005],RU[1005][1005],UU[1005][1005];
int LS[1005][1005],RS[1005][1005],US[1005][1005];
char c[1005][1005];

void init(){
scanf("%d%d",&m,&n);
for (int i=1;i<=m;i++)
scanf("%s",&c[i][1]);
}

void solve(){
int i,j;
memset(LS,0,sizeof(LS));
memset(RS,0,sizeof(RS));
memset(LU,0,sizeof(LU));
memset(RU,0,sizeof(RU));

long long ans=0;
for (i=1;i<=m;i++){
for (j=1;j<=n;j++){
LU[i][j]=LU[i][j-1]+LS[i][j-1];
LS[i][j]=LS[i][j-1];
if (c[i][j]==’M’){
LS[i][j]++;
ans+=LU[i][j];
}
}
for (j=n;j>=1;j–){
RU[i][j]=RU[i][j+1]+RS[i][j+1];
RS[i][j]=RS[i][j+1];
if (c[i][j]==’M’) RS[i][j]++;
}
for (j=1;j<=n;j++){
UU[i][j]=UU[i-1][j]+US[i-1][j];
US[i][j]=US[i-1][j];
if (c[i][j]==’M’){
US[i][j]++;
ans+=UU[i][j];
}
}

for (j=1;j<=n;j++){
if (c[i][j]==’M’)
ans+=LU[i-1][j-1]+LS[i-1][j-1]+RU[i-1][j+1]+RS[i-1][j+1];
LU[i][j]+=LU[i-1][j-1]+LS[i-1][j-1]+UU[i-1][j]+US[i-1][j];
LS[i][j]+=LS[i-1][j-1]+US[i-1][j];
RU[i][j]+=RU[i-1][j+1]+RS[i-1][j+1]+UU[i-1][j]+US[i-1][j];
RS[i][j]+=RS[i-1][j+1]+US[i-1][j];
}
}

printf("%lld",ans);
}

int main(){
init();
solve();
printf(" ");
for (int i=1;i<=m;i++)
for (int j=1;j<=n;j++){
if (c[i][j]==’M’) c[i][j]=’.’;
if (c[i][j]==’S’) c[i][j]=’M’;
}
solve();
printf("n");
}

[COCI 2009/2010 – Constest #7 SVEMIR]10^5个点的完全图的最小生成树、堆、并差集、暴力解法+求正解~

【题目地址】http://evaluator.hsin.hr/login.php?redirect=index.php
【题目大意】
给定N<=10^5个点,每个点有一个三维坐标(Xi,Yi,Zi)
两个点间的距离定义为Distance=max(|Xi-Xj|,|Yi-Yj|,|Zi-Zj|)。
然后让你求它的最小生成树。
【算法分析】
标题是虽然是事实,但是明显是吓人的。。。。(为啥我也变成标题党了= =)
然后这题我的做法非常暴力
我的方法如下(由于难以言表,请尽量结合程序围观。。。):
首先必然的一件事是:用的kruskal  (MS拼错了,谁来纠正一下。。。)
先把点分开三个,分到不同的数组里,分别按x,y,z排序。
然后每个点设置一个已走步长:Lena[i] Lenb[i] Lenc[i]。
再建3个堆。
分别装的key值是类似这种a[i+Lena[i]].x-a[i].x。
然后每次取a,b,c三个堆中key值最小的出来,然后kruskal。
然后再把Lena[i]+1,再次把a[i+Lena[i]].x-a[i].x放入堆中。
(因为这个数肯定是增大了,所以能保证先把小的边弄了。)
最后并差集弄一下,就是一个完整的超暴力kruskal。
【其他】
Test # Score Time Memory Result 1 10 0.00s 9760 kB Correct! 2 10 0.00s 9760 kB Correct! 3 10 0.00s 9760 kB Correct! 4 10 0.00s 9760 kB Correct! 5 10 0.00s 9760 kB Correct! 6 10 0.04s 9920 kB Correct! 7 10 0.31s 9760 kB Correct! 8 10 0.30s 9760 kB Correct! 9 10 0.47s 9760 kB Correct! 10 10 0.80s 9760 kB Correct!
期待众神牛讲出正解。毕竟做人不能那么暴力。
【CODE】
#include #include #include const int N=100005;

struct Heap_Type{
int tot;
struct Node{int pos,key;}d[N],tmp;

void swap(Node &x,Node &y){tmp=x; x=y; y=tmp;}

void up(int k){
while (k>1){
if (d[k].key swap(d[k],d[k/2]);
k/=2;
}else break;
}
}

void down(int k){
int p;
while (k*2<=tot){
p=k*2;
if (p+1<=tot && d[p+1].key if (d[p].key swap(d[p],d[k]);
k=p;
}else break;
}
}

void ins(int key,int pos){
tot++;
d[tot].key=key;
d[tot].pos=pos;
up(tot);
}

void del(){
swap(d[1],d[tot]);
tot–;
down(1);
}
}Heapa,Heapb,Heapc;
struct Point{int x,y,z,pos;}a[N],b[N],c[N];
int n,times;
int F[N],Num[N],Lena[N],Lenb[N],Lenc[N];
long long ans;

int cmpa(const void *x,const void *y){return ((Point*)x)->x-((Point*)y)->x;}
int cmpb(const void *x,const void *y){return ((Point*)x)->y-((Point*)y)->y;}
int cmpc(const void *x,const void *y){return ((Point*)x)->z-((Point*)y)->z;}

void init(){
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
a[i].pos=i;
c[i]=b[i]=a[i];
Lena[i]=Lenb[i]=Lenc[i]=1;
F[i]=i; Num[i]=1;
}
qsort(a+1,n,sizeof(Point),cmpa);
qsort(b+1,n,sizeof(Point),cmpb);
qsort(c+1,n,sizeof(Point),cmpc);
Heapa.tot=Heapb.tot=Heapc.tot=0;
for (int i=1;i Heapa.ins(a[i+1].x-a[i].x,i);
Heapb.ins(b[i+1].y-b[i].y,i);
Heapc.ins(c[i+1].z-c[i].z,i);
}
}

int GF(int p){
int res=p,tmp;
while (F[res]!=res) res=F[res];
while (p!=res){
tmp=F[p];
F[p]=res;
p=tmp;
}
return res;
}

inline bool set_union(int x,int y){
if (GF(x)==GF(y)) return false;
times++;
if (Num[F[x]] Num[F[y]]+=Num[F[x]];
F[F[x]]=F[y];
}else{
Num[F[x]]+=Num[F[y]];
F[F[y]]=F[x];
}
return true;
}

void solve(){
times=1; ans=0;
int i;
while (times if (Heapa.d[1].key<=Heapb.d[1].key && Heapa.d[1].key<=Heapc.d[1].key){
i=Heapa.d[1].pos;
if (set_union(a[i].pos,a[i+Lena[i]].pos)) ans+=Heapa.d[1].key;
Lena[i]++;
Heapa.del();
if (i+Lena[i]<=n) Heapa.ins(a[i+Lena[i]].x-a[i].x,i);
}else
if (Heapb.d[1].key<=Heapa.d[1].key && Heapb.d[1].key<=Heapc.d[1].key){
i=Heapb.d[1].pos;
if (set_union(b[i].pos,b[i+Lenb[i]].pos)) ans+=Heapb.d[1].key;
Lenb[i]++;
Heapb.del();
if (i+Lenb[i]<=n) Heapb.ins(b[i+Lenb[i]].y-b[i].y,i);
}
else{
i=Heapc.d[1].pos;
if (set_union(c[i].pos,c[i+Lenc[i]].pos)) ans+=Heapc.d[1].key;
Lenc[i]++;
Heapc.del();
if (i+Lenc[i]<=n) Heapc.ins(c[i+Lenc[i]].z-c[i].z,i);
}
}
printf("%lldn",ans);
}

int main(){
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
init();
solve();
}