GDKOI之旅

这次GDKOI总的来说比较遗憾,但是也不算太差。。。

给AekdyCoin师傅丢脸了。。。

首先说下题目类型(后面的是题目分值):

Day1

1:Floyed——30分

2:基于连通性的状态压缩动态规划——40分

3:找循环节,然后比较繁琐的处理——40分

4:IMBA的压轴题,构造简单割处理,转化比较牛B,很可惜居然这题是上一年winter camp上的原题,而且当时的出题人也在参加比赛。。。无语——40分

Day2

1:直接积分 or 利用导数求出单调性,发现是单峰函数,可以二分 or 直接推导出答案O(1),总的来说是数学题——30分

2:简单的DP——40分

3:双向BFS——40分

4:平衡树连边再处理。主要是这题我推不出那个边数必然为O(N)规模的这一结论。

我的情况:

Day1:

1:AC

2:暴力DFS拿了90%的分数。。。

3:悲剧,怎么拍都有BUG,于是只拿30%分数。

4:被秒杀。。。55555555,被虐了,用了个状态压缩DP,拿了30%分数。

Day2:

1:AC

2:居然10分钟敲的DP写错了。。。我无语,直接丢32分。。。。

3:双向BFS写出来了,不过操作步数为0的情况没有特判,WA1个点。拿到36分。

4:居然暴力都写错,12分就这样没了。

假设是当前水平下,最好状态:

Day1第3题过掉。+28分

Day2第2题DP写对。+32分

Day2第3题那个点拿掉。+4分

Day2第4题写对。+12分。

总共可以+76分,但是毕竟比赛不能说都能做出来,也算是这样了。。

最后并列第10,前面有两个是高三拿了NOI金牌回来FUN的。。。

总的来说比较遗憾,下次要减少这些SB失误唉。。。

[ZOJ 3297 Cookie Choice II]头尾指针维护

【题目大意】

就是找一个最短连续子序列,使得对于每个i,min[i]<=sum(i)<=max[i]

【算法分析】

很简单的头尾指针维护。

不过要注意题目有负数等无关数字,无视即可(只增加长度)。

然后由于满足单调性我们维护一个最短的区间使得其满足所有的min

然后判断这时候符不符合max即可。

【其它】比赛时1A

【CODE】

#include #include int n,kind,ans;
int hash[3000],a[401111],min[3000],max[3000];

void work(){
    ans=0x7FFFFFFF;
    int i,j=0,que=0,more=0;
    for (i=1;i<=kind;i++){
      if (min[i]>0) que++;
      if (max[i]<0) more++;
    }   
    for (i=1;i<=n;i++){
        while (j            j++;
            if (a[j]>=1 && a[j]<=kind){
              hash[a[j]]++;
              if (hash[a[j]]==max[a[j]]+1) more++;
              if (hash[a[j]]==min[a[j]]) que–;
            }   
        }
        if (!que && !more && j-i+1        if (a[i]>=1 && a[i]<=kind){
            hash[a[i]]–;
            if (hash[a[i]]==min[a[i]]-1) que++;
            if (hash[a[i]]==max[a[i]]) more–;
        }   
    }   
}   

int main(){
    while (scanf("%d%d",&n,&kind)!=EOF){
        for (int i=1;i<=n;i++) scanf("%d",&a[i]);
        for (int i=1;i<=kind;i++){
            scanf("%d%d",&min[i],&max[i]);
        }   
        memset(hash,0,sizeof(hash));
        work();
        if (ans==0x7FFFFFFF) printf("-1n");
        else printf("%dn",ans);
    }   
}   

[ZOJ 3304 Prison Break]BFS、模拟、种子染色法

【题目大意】

如果把P视作不能去的区域,哪个人不能通过上下左右走到达牢房边缘的话,直接就变成Ghost

然后在剩下的人里,找最大的上下左右对角线连通的连通块。

【算法分析】

一开始处理Ghost的话,从牢房边缘bfs进来,如果不能到达某个P,他就死了。

然后剩下的就是种子染色法了。

【CODE】

#include #include int m,n,lx[1111111],ly[1111111],ans,head,tail;
char map[1111][1111];
bool v[1111][1111];

inline void expand1(int tx,int ty){
    if (tx<1 || tx>m || ty<1 || ty>n || v[tx][ty]) return;
    v[tx][ty]=true;
    tail++;
    lx[tail]=tx;
    ly[tail]=ty;
}   

void getghost(){
    head=0; tail=0;
    for (int i=1;i<=m;i++){
        tail++;
        lx[tail]=i;
        ly[tail]=0;
        tail++;
        lx[tail]=i;
        ly[tail]=n+1;
    }   
    for (int i=1;i<=n;i++){
        tail++;
        lx[tail]=0;
        ly[tail]=i;
        tail++;
        lx[tail]=m+1;
        ly[tail]=i;
    }
    while (head        head++;
        if (map[lx[head]][ly[head]]==’P’ && lx[head]>0 && lx[head]<=m && ly[head]>0 && ly[head]<=n)
          continue;
        expand1(lx[head]-1,ly[head]);
        expand1(lx[head]+1,ly[head]);
        expand1(lx[head],ly[head]-1);
        expand1(lx[head],ly[head]+1);
    }   
    for (int i=1;i<=m;i++)
      for (int j=1;j<=n;j++)
        if (map[i][j]==’P’ && !v[i][j])
          map[i][j]=’G’;
}

inline void expand(int tx,int ty){
    if (tx<1 || tx>m || ty<1 || ty>n || v[tx][ty] || map[tx][ty]!='P') return;
    v[tx][ty]=true;
    tail++;
    lx[tail]=tx;
    ly[tail]=ty;
}   

void bfs(int sx,int sy){
    head=0,tail=1;
    lx[1]=sx; ly[1]=sy;
    v[sx][sy]=true;
    while (head        head++;
        expand(lx[head]-1,ly[head]);
        expand(lx[head]+1,ly[head]);
        expand(lx[head],ly[head]-1);
        expand(lx[head],ly[head]+1);
        expand(lx[head]-1,ly[head]-1);
        expand(lx[head]-1,ly[head]+1);
        expand(lx[head]+1,ly[head]-1);
        expand(lx[head]+1,ly[head]+1);
    }   
    if (tail>ans) ans=tail;
}   

void solve(){
    memset(map,’P’,sizeof(map));
    memset(v,false,sizeof(v));
    for (int i=1;i<=m;i++)
      for (int j=1;j<=n;j++)
        for (map[i][j]=getchar();map[i][j]==’ ‘ || map[i][j]==’n’;map[i][j]=getchar());
    getghost();
    memset(v,false,sizeof(v));
    ans=0;
    for (int i=1;i<=m;i++)
      for (int j=1;j<=n;j++)
        if (map[i][j]==’P’ && !v[i][j])
          bfs(i,j);
    printf("%dn",ans);
}   

int main(){
    while (scanf("%d%d",&m,&n)!=EOF) solve();
    return 0;   
}   

[ZOJ 3301 Make Pair]排序、贪心

【题目大意】

给偶数个人分组,使得组员的体重相差值之和最小。

【算法分析】

该次月赛的送分题。

显然,排序以后按顺序两两匹配即可。

证明:

若a<=b<=c<=d

即证明:d-c+b-a<=d-a+c-b

推导出:b<=c

符合条件,所以得证。

【CODE】

#include #include #include #include #include using namespace std;
struct datatype{int d,pos;}a[11111];
int n;

inline bool cmp(datatype x,datatype y){
    return x.d}   

int main(){
    int tc=0;
    while (scanf("%d",&n)!=EOF){
        tc++;
        if (tc!=1) printf("n");
        for (int i=1;i<=n;i++) scanf("%d",&a[i].d);
        for (int i=1;i<=n;i++) a[i].pos=i;
        sort(&a[1],&a[n+1],cmp);
        for (int i=1;i          printf("%d %dn",a[i].pos,a[i+1].pos);
    }   
}   

[ZOJ 3300 Mahjong]暴力DFS

【题目大意】

给出13张牌(1~9),问摸到什么牌能赢。把所有方案在同一行输出。

【算法分析】

暴力DFS,其实有更好的复杂度为O(9*9)的方法,GDKOI上有原题。。。

但是这题规模太小了,直接暴力

【CODE】

#include #include #include #include using namespace std;

int a[20],h[20],num;
bool flag;

void dfs(int i){
    if (flag) return;
    if (num==0){
        flag=true;
        return;
    }   
    while (h[i]==0) i++;
    if (h[i]>=3){
        h[i]-=3;
        num-=3;
        dfs(i);
        h[i]+=3;
        num+=3;
    }   
    if (h[i] && h[i+1] && h[i+2]){
        h[i]–; h[i+1]–; h[i+2]–;
        num-=3;
        dfs(i);
        num+=3;
        h[i]++; h[i+1]++; h[i+2]++;
    }   
}   

bool tryit(){
    flag=false;
    num=12;
    dfs(1);
    return flag;
}   

bool solve(){
    memset(h,0,sizeof(h));
    for (int i=1;i<=14;i++){
        h[a[i]]++;
      }   
    for (int i=1;i<=9;i++)
      if (h[i]>4) return false;
    for (int i=1;i<=9;i++)
      if (h[i]>=2){
          h[i]-=2;
          if (tryit()) return true;
          h[i]+=2;
      }   
    return false;
}   

int main(){
    for (;;){
        if (scanf("%d",&a[1])==EOF) break;
        for (int i=2;i<=13;i++) scanf("%d",&a[i]);
        bool st=false;
        for (int i=1;i<=9;i++){
            a[14]=i;
            if (solve()){
                if (st) printf(" ");
                printf("%d",i);
                st=true;
            }   
        }   
        printf("n");
    }   
}