[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();
}

[COCI 2009/2010 – Constest #7 BAKICE]排序、模拟

【题目地址】http://evaluator.hsin.hr/login.php?redirect=index.php
【题目大意】
。。。不想写了,等下有时间或许会补一下。
【算法分析】
看规模觉得很假。
于是直接暴力把所有点对取出来按距离排序。
然后贪心的取。
其实也不叫贪心了,应该说按题目那样模拟。
然后~,Orz,居然0MS AC了。。。
【CODE】
#include #include #include #include #define sqr(x) ((x)*(x))
const int N=105;
const int INF=1000000000;
struct Queue{int x[N*N],y[N*N],t;}L,R;
struct edge{int x,y;}g[4000000];
bool v[N*N],Break[N*N];
int m,n,e,ans,link[N*N];
char c[N][N];

inline int dis(int i,int j){return sqr(L.x[i]-R.x[j])+sqr(L.y[i]-R.y[j]);}
inline int cmp(const void *x,const void *y){
return dis( ((edge*)x)->x, ((edge*)x)->y )
– dis( ((edge*)y)->x, ((edge*)y)->y );
}

void init(){
L.t=R.t=e=0;
int i,j;
scanf("%d%d",&m,&n);
for (i=1;i<=m;i++)
for (j=1;j<=n;j++)
for (;c[i][j]!=’.’ && c[i][j]!=’X’ && c[i][j]!=’L’;c[i][j]=getchar());
for (i=1;i<=m;i++)
for (j=1;j<=n;j++)
if (c[i][j]==’X’){
L.t++;
L.x[L.t]=i;
L.y[L.t]=j;
}
else if (c[i][j]==’L’){
R.t++;
R.x[R.t]=i;
R.y[R.t]=j;
}
for (i=1;i<=L.t;i++)
for (j=1;j<=R.t;j++){
e++;
g[e].x=i; g[e].y=j;
}
qsort(&g[1],e,sizeof(edge),cmp);
}

void solve(){
memset(v,false,sizeof(v));
memset(link,0,sizeof(link));
memset(Break,false,sizeof(Break));
ans=0;
int i,j,k;
for (k=1;k<=e;k++){
i=g[k].x; j=g[k].y;
if (v[i]) continue;
if (!v[i] && !link[j]){
v[i]=true;
link[j]=i;
continue;
}
if (dis(i,j)==dis(link[j],j)){
if (!Break[j]) ans++;
Break[j]=true;
v[i]=true;
}
}
printf("%dn",ans);
}

int main(){
// freopen("bakice.in","r",stdin);
// freopen("bakice.out","w",stdout);
init();
solve();
}

[COCI 2009/2010 – Constest #7 COKOLADA]对二进制数的理解

【题目链接】http://evaluator.hsin.hr/login.php?redirect=index.php
【题目大意】
给出一个尺寸N。
你需要取一个2^k (k是任你选的)的巧克力出来,然后切若干刀(每刀把一个巧克力切开成两半一样大小的)
最终在其中取出若干个块巧克力,使得加起来的尺寸等于N。
最终输出2^k和切得刀数。
在保证2^k最小的前提下,切刀数要最少。
【算法分析】
同属于被秒杀题= =
假如N=2^k,那么直接输出  2^k 0
否则输出最小的一个k满足,N<2^k (用log2求就可以了),
然后输出将n变成二进制以后从个位数上去的第一个“1”和k的差即可。
【其它】
YY一下就懂了。
【CODE】
#include #include #include int n,LG,i;
scanf("%d",&n);
LG=(int)(log(n)/log(2)+1e-7);
if (1< else{
LG++;
i=0;
while (n%2==0){
i++;
n/=2;
}
printf("%d %dn",1< }
}

[COCI 2009/2010 – Constest #7 SPAVANAC]水题

【题目地址】http://evaluator.hsin.hr/login.php?redirect=index.php
【题目大意】
给出一个24小时制的时间,让你输出它的前45分钟时多少。
【算法分析】
类a-b problems
【其它】
。。。其实我不想写的,但是为了完整性,还是写一下。。。
【CODE】
#include int main(){
int H,M;
scanf("%d%d",&H,&M);
M-=45;
if (M<0){M+=60; H--;}
if (H<0) H+=24;
printf("%d %dn",H,M);
}