第三周 5.31-6.6

5.31

 

2015年百度之星程序设计大赛 - 初赛(1) 1001 超级赛亚ACMer

竟然看错题了。要哭了。

“如果百小度的战斗力大于对方,那么百小度就会轻易获胜,得不到锻炼并且骄傲起来,他以后的战斗力将保持在这个值,再也不会发生改变。

贪心。每次打能持续爆超赛的人中最厉害的。能打过最后一个就好。

 

搞完读书笔记回来码。发现好像看错题并不影响过程。因为比我弱的我都是最后打的。

于是还是觉得自己当时码的没有错。然后就很费解为何会WA了。

最后发现好像是没有用LL嘛。//再也不相信爱情了

(不过怎么看都觉得自己的过程比拓神铖霸的烦好多)

 1 # include <iostream>
 2 # include <cstdio>
 3 # include <algorithm>
 4 using namespace std;
 5 typedef long long LL;
 6 LL num[10005];
 7 
 8 int main(void)
 9 {
10     int T;cin>>T;
11     for(int kase=1;kase<=T;kase++)
12     {
13         int n,m,k,index=0,ok=1;
14         scanf("%d%d%d",&n,&m,&k);
15         for(int i=1;i<=n;i++) scanf("%I64d",num+i);
16         sort(num+1,num+1+n);
17         while(index<n)
18             if(num[index+1]<=m) index++;
19             else break;
20         if(!index) {printf("Case #%d:\nmadan!\n",kase);continue;}
21         LL tem=num[index];
22         while(index<n)
23         {
24             ok=0;
25             for(int i=index;i<n;i++)
26                 if(num[i+1]<=tem+max(0,k)) {ok=1;index=i+1;}
27                 else break;
28             if(!ok) break;
29             tem=num[index];k--;
30         }
31         if(!ok) printf("Case #%d:\nmadan!\n",kase);
32         else printf("Case #%d:\nwhy am I so diao?\n",kase);
33     }
34     return 0;
35 }
Aguin

 

下午又玩了一场百度之星。然而只做了一个。

2015年百度之星程序设计大赛 - 初赛(2) 1003 棋盘占领

每次把新增的黑点放进队列,检查它四周有没有能被黑化的白点。

 1 # include <iostream>
 2 # include <cstdio>
 3 # include <queue>
 4 # include <cstring>
 5 using namespace std;
 6 int map[501][501],MOVE[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
 7 
 8 int main(void)
 9 {
10     int T;cin>>T;
11     for(int kase=1;kase<=T;kase++)
12     {
13         int n,m,g; scanf("%d%d%d",&n,&m,&g);
14         int ans=g;
15         memset(map,0,sizeof(map));
16         queue< pair<int,int> > q1,q2;
17         for(int i=0;i<g;i++)
18         {
19             int x,y;scanf("%d%d",&x,&y);
20             if(map[x][y]) ans--;
21             else{ map[x][y]=1; q1.push(make_pair(x,y)); }
22         }
23         while(!q1.empty())
24         {
25             int x=q1.front().first,y=q1.front().second; q1.pop();
26             for(int i=0;i<4;i++)
27                 if(x+MOVE[i][0]>=1&&x+MOVE[i][0]<=n&&y+MOVE[i][1]>=0&&y+MOVE[i][1]<=m&&!map[x+MOVE[i][0]][y+MOVE[i][1]])
28                     q2.push(make_pair(x+MOVE[i][0],y+MOVE[i][1]));
29             while(!q2.empty())
30             {
31                 int a=q2.front().first,b=q2.front().second; q2.pop();
32                 int ok=0;
33                 if(a>1&&b>1&&map[a][b-1]&&map[a-1][b]) ok=1;
34                 else if(a>1&&b<m&&map[a-1][b]&&map[a][b+1]) ok=1;
35                 else if(a<n&&b>1&&map[a+1][b]&&map[a][b-1]) ok=1;
36                 else if(a<n&&b<m&&map[a+1][b]&&map[a][b+1]) ok=1;
37                 if(ok) {map[a][b]=1; q1.push(make_pair(a,b));ans++;}
38             }
39         }
40         printf("Case #%d:\n%d\n",kase,ans);
41     }
42     return 0;
43 }
Aguin

 

后面出了点问题。搞不定。明天再看吧。

 

6.1

 

儿童节快乐。

2015年百度之星程序设计大赛 - 初赛(2) 1002 连接的管道

昨天被这个题整的蛮苦的。

因为第一眼看到觉得是最小生成树。于是最先写了。

当时大部分人应该是先写dp。然而并不会。

不知道哪个快。写的Prim。

写完第一发随手开爆M了。当时用的向量存图。

改成结构体存图。继续爆M。

后来发现再存一次边是多余的。然后又爆T了。就写别的去了。

 

然而后来去hdu上补题的时候。没改过的代码竟然过了。

可能hdu和BC的机子不一样吧TAT。

多跑了几次。有出现.9s+的情况。在比赛的时候很容易跪吧。

 1 # include <iostream>
 2 # include <cstdio>
 3 # include <cmath>
 4 # include <cstring>
 5 # include <queue>
 6 using namespace std;
 7 # define CLR(x) memset(x,0,sizeof(x))
 8 typedef long long LL;
 9 int map[1001][1001],MOVE[4][2]={-1,0,1,0,0,-1,0,1};
10 bool vis[1001][1001];
11 
12 struct node
13 {
14     int i,j,value;
15     friend bool operator < (node a, node b)
16     {
17         return a.value > b.value;
18     }
19 };
20 
21 int main(void)
22 {
23     int T;cin>>T;
24     for(int kase=1;kase<=T;kase++)
25     {
26         int N,M;scanf("%d%d",&N,&M);
27         for(int i=1;i<=N;i++)
28             for(int j=1;j<=M;j++)
29                 scanf("%d",&map[i][j]);
30         priority_queue < node > q;
31         LL ans=0; CLR(vis); vis[1][1]=1;
32         node x;
33         x.i=1;x.j=2;x.value=abs(map[1][1]-map[1][2]); q.push(x);
34         x.i=2;x.j=1;x.value=abs(map[1][1]-map[2][1]); q.push(x);
35         while(!q.empty())
36         {
37             int tem=q.top().value,toi=q.top().i,toj=q.top().j; q.pop();
38             if(!vis[toi][toj])
39             {
40                 vis[toi][toj]=1; ans+=tem;
41                 for(int i=0;i<4;i++)
42                     if(toi+MOVE[i][0]>=1&&toi+MOVE[i][0]<=N&&toj+MOVE[i][1]>=1&&toj+MOVE[i][1]<=M&&!vis[toi+MOVE[i][0]][toj+MOVE[i][1]])
43                     {
44                         x.i=toi+MOVE[i][0];x.j=toj+MOVE[i][1];
45                         x.value=abs(map[toi][toj]-map[x.i][x.j]); q.push(x);
46                     }
47             }
48         }
49         printf("Case #%d:\n%I64d\n",kase,ans);
50     }
51     return 0;
52 }
Aguin

 

不知道Kruskal会不会快一些。于是推了重写。

存图的时候又爆M了。但是看见一个别人的程序。数组开的都比我大。却没有爆M。好费解。

结果是跑的要比Prim快一些拉。

当时笔记上记的是边多用Prim。但是对于多与少并没有概念QAQ

# include <iostream>
# include <cstdio>
# include <cmath>
# include <algorithm>
using namespace std;
# define I(x) ( ( x/M ) + ( x%M ? 1:0 ) )
# define J(x) ( x%M ? x%M : M )
# define ID(i,j) ( ( i-1 ) * M + j )
# define maxn 1000001
typedef long long LL;
int h[maxn],pa[maxn];

int fa(int x)
{
    return pa[x]==x?x:pa[x]=fa(pa[x]);
}

struct node
{
    int from,to,value;
} edge[2*maxn];

bool cmp(node a,node b)
{
    return a.value<b.value;
}

int main(void)
{
    int T;cin>>T;
    for(int kase=1;kase<=T;kase++)
    {
        int N,M;scanf("%d%d",&N,&M);
        for(int i=1;i<=N*M;i++)  { pa[i]=i; scanf("%d",h+i); }
        int num=0;
        for(int i=1;i<N;i++)
            for(int j=1;j<=M;j++)
                {
                    num++;
                    edge[num].from=ID(i,j);edge[num].to=ID(i+1,j);
                    edge[num].value=abs( h[edge[num].from]-h[edge[num].to] );
                }
        for(int j=1;j<M;j++)
            for(int i=1;i<=N;i++)
                {
                    num++;
                    edge[num].from=ID(i,j);edge[num].to=ID(i,j+1);
                    edge[num].value=abs( h[edge[num].from]-h[edge[num].to] );
                }
        sort(edge+1,edge+1+num,cmp);
        LL ans=0; int cnt=0;
        for(int i=1;i<=num;i++)
            if(cnt==M*N-1) break;
            else if(fa(edge[i].from)!=fa(edge[i].to))
            {
                cnt++; ans+=edge[i].value;
                pa[fa(edge[i].to)]=pa[fa(edge[i].from)];
            }
        printf("Case #%d:\n%I64d\n",kase,ans);
    }
    return 0;
}
Aguin

 

6.2

想补题的。码了好久。吃一发T。

偏偏是这种忙的时候。感觉又浪费时间了。

心累。不码了。

 

 

大概过了一个多小时,想想反正浪费了那么多时间了。再浪费一些吧。破罐子破摔了。

2015年百度之星程序设计大赛 - 初赛(1) 1002 找连续数

先贴一个T掉的sb线段树。

 1 # include <iostream>
 2 # include <cstdio>
 3 # include <algorithm>
 4 # include <cstring>
 5 using namespace std;
 6 int num[10001],cnt[1001];
 7 
 8 struct node
 9 {
10     int a,b,max,min;
11 } tree[10001*4];
12 
13 void maketree(int i,int a,int b)
14 {
15     tree[i].a=a;tree[i].b=b;
16     if(a==b)
17     {
18         tree[i].max=tree[i].min=num[a];
19         return;
20     }
21     maketree(2*i,a,(a+b)/2);
22     maketree(2*i+1,(a+b)/2+1,b);
23     tree[i].max=max(tree[2*i].max,tree[2*i+1].max);
24     tree[i].min=min(tree[2*i].min,tree[2*i+1].min);
25     return;
26 }
27 
28 int MAX(int i,int a,int b)
29 {
30     if(a<=tree[i].a&&tree[i].b<=b) return tree[i].max;
31     if(b<=(tree[i].a+tree[i].b)/2) return MAX(2*i,a,b);
32     if(a>=(tree[i].a+tree[i].b)/2+1) return MAX(2*i+1,a,b);
33     return max(MAX(2*i,a,b),MAX(2*i+1,a,b));
34 }
35 
36 int MIN(int i,int a,int b)
37 {
38     if(a<=tree[i].a&&tree[i].b<=b) return tree[i].min;
39     if(b<=(tree[i].a+tree[i].b)/2) return MIN(2*i,a,b);
40     if(a>=(tree[i].a+tree[i].b)/2+1) return MIN(2*i+1,a,b);
41     return min(MIN(2*i,a,b),MIN(2*i+1,a,b));
42 }
43 
44 int main(void)
45 {
46     int n,m; scanf("%d%d",&n,&m);
47     for(int i=1;i<=n;i++) scanf("%d",num+i);
48     maketree(1,1,n);
49     printf("Case #1:\n");
50     while(m--)
51     {
52         int k,ans=0;scanf("%d",&k);
53         for(int i=1;i+k-1<=n;i++)
54         {
55             int Max=MAX(1,i,i+k-1),Min=MIN(1,i,i+k-1);
56             if(Max-Min==k-1)
57             {
58                  int ok=1;
59                  memset(cnt,0,sizeof(cnt));
60                 for(int j=i;j<i+k;j++) cnt[num[j]-Min]++;
61                 for(int j=0;j<k;j++)
62                     if(cnt[j]>1) {ok=0;break;}
63                 if(ok) ans++;
64             }
65         }
66         printf("%d\n",ans);
67     }
68     return 0;
69 }
Aguin

看见最值就想写线段树阿。誰知道会这样呢。

写了个暴力。交了十几次。竟然过了几次。(上面那个一次都没过)

抄了个优化。过了。然而。不开心。

 1 # include <iostream>
 2 # include <cstdio>
 3 # include <cstring>
 4 using namespace std;
 5 int num[10001]={0},cnt[1001];
 6 
 7 int main(void)
 8 {
 9     int n,m; scanf("%d%d",&n,&m);
10     for(int i=1;i<=n;i++) scanf("%d",num+i);
11     printf("Case #1:\n");
12     while(m--)
13     {
14         int k,ans=0;scanf("%d",&k);
15         for(int i=1;i+k-1<=n;i++)
16         {
17             int MAX,MIN;
18             if(i!=1&&num[i-1]!=MAX&&num[i-1]!=MIN)
19             {
20                 if(num[i+k-1]>MAX) MAX=num[i+k-1];
21                 if(num[i+k-1]<MIN) MIN=num[i+k-1];
22             }
23             else
24             {
25                 MAX=num[i],MIN=num[i];
26                 for(int j=1;j<k;j++)
27                 {
28                     if(MAX<num[i+j]) MAX=num[i+j];
29                     if(MIN>num[i+j]) MIN=num[i+j];
30                 }
31             }
32             if(MAX-MIN==k-1)
33             {
34                 int ok=1;
35                 memset(cnt,0,sizeof(cnt));
36                 for(int j=i;j<i+k;j++) cnt[num[j]-MIN]++;
37                 for(int j=0;j<k;j++)
38                     if(cnt[j]>1) {ok=0;break;}
39                    if(ok) ans++;
40             }
41         }
42         printf("%d\n",ans);
43     }
44     return 0;
45 }
Aguin

 

6.3

2015年百度之星程序设计大赛 - 初赛(1) 1005 三阶魔方

当时打第一场的时候发现都不会。这道题少有人交。但还是选择了码这道。

一开始数据出错了。但大部分的人是觉得麻烦不想写吧。

 

记得刚进A协的时候。司老大讲了置换。那时候做了一个好烦的置换。

写了好几天。写的又丑又长。而且Uva还出错了。

找司老大帮忙。他叫我重新看置换有没写错。后来找不出错就搁置在那。

后来过了几天再交了一次就过了。好开心的。

 

比赛的时候WA了。后来发现是只考虑了块的位置。忘记了方向。

(还挺喜欢魔方的。好惭愧。娱乐向。非竞速党。)

 

在贴吧看见一个帖子。乌木老师讲了盲拧中的色向。然而并不了解色向和的计算。

Link:http://tieba.baidu.com/p/3795808536

于是选择了蠢蠢的办法。就是给54个面标号……

写完代码又是丑丑的。不知道怎么标号会好看些阿。

 1 # include <iostream>
 2 # include <cstdio>
 3 # include <cstring>
 4 using namespace std;
 5 typedef unsigned long long ULL;
 6 int cube[54],cpy[54],cnt[54];
 7 
 8 ULL gcd(ULL x,ULL y)
 9 {
10     return (x%y==0)? y : gcd(y,x%y);
11 }
12 
13 ULL lcm(ULL x,ULL y)
14 {
15     return (x*y)/gcd(x,y);
16 }
17 
18 void change(int x1,int x2,int x3,int x4)
19 {
20     cube[x1]=cpy[x2];cube[x2]=cpy[x3];cube[x3]=cpy[x4];cube[x4]=cpy[x1];
21     return;
22 }
23 
24 void move(char c)
25 {
26     if(c=='U'){change(18,24,26,20);change(21,25,23,19);change(0,9,29,38);change(1,10,28,37);change(2,11,27,36);}
27     if(c=='R'){change(10,12,16,14);change(9,15,17,11);change(20,2,53,35);change(23,5,50,32);change(26,8,47,29);}
28     if(c=='F'){change(1,3,7,5);change(0,6,8,2);change(24,42,53,9);change(25,39,52,12);change(26,36,51,15);}
29     if(c=='D'){change(53,51,45,47);change(52,48,46,50);change(6,44,35,15);change(7,43,34,16);change(8,42,33,17);}    
30     if(c=='L'){change(36,38,44,42);change(37,41,43,39);change(24,27,45,6);change(21,30,48,3);change(18,33,51,0);}    
31     if(c=='B'){change(27,29,35,33);change(30,28,32,34);change(18,11,47,44);change(19,14,46,41);change(20,17,45,38);}
32     memcpy(cpy,cube,sizeof(cpy));
33     return;
34 }
35 
36 int main(void)
37 {
38     int T;cin>>T;getchar();
39     for(int kase=1;kase<=T;kase++)
40     {
41         for(int i=0;i<54;i++)
42             cube[i]=cpy[i]=i;
43         char s[105];gets(s);
44         int len=strlen(s);
45         for(int i=0;i<len;i++) if(s[i]=='\''||s[i]=='2') {char t=s[i];s[i]=s[i-1];s[i-1]=t;}
46         for(int i=0;i<len;)
47             if(s[i]=='\'') {move(s[i+1]);move(s[i+1]);move(s[i+1]);i+=2;}
48             else if(s[i]=='2') {move(s[i+1]);move(s[i+1]);i+=2;}
49             else{ move(s[i]); i++;}
50         memset(cpy,0,sizeof(cpy));
51         memset(cnt,0,sizeof(cnt));
52         for(int i=0;i<54;i++)
53             if(!cpy[i])
54             {
55                 int t=i,k=0;
56                 while(!cpy[t]) { k++; cpy[t]=1; t=cube[t];}
57                 cnt[k]=1;
58             }
59         ULL ans=1;
60         for(int i=1;i<=54;i++) if(cnt[i]) ans=lcm(ans,i);
61         printf("Case #%d:\n%I64d\n",kase,ans);
62     }
63     return 0;
64 }
Aguin

 

6.4

补一个题。WA一晚。再战。

 

6.5

TAT 忙 一天没码程序噜。

 

6.6

2015年百度之星程序设计大赛 - 初赛(1) 1004 KPI

拖了两天的题目。

郏老大曾经曰过:动态维护第k值这种千古经典问题一向有很多解决办法:线段树、树状数组、平衡树等……

当年补Black Box的时候 用的两个堆对顶。

学了线段树和树状数组后想试试看拉。

先离散化。再用二分法查询。

一开始以为二分写错了。后来发现离散化就写错了- -

以前做过两个离散化。都是那种把原象映射到象后不需要再用到原象的。(不知道怎么表达 大概是这个意思)

这个需要再映射回去。不敢再用map了。T怕了。

就去抄了一个离散化。还是二分查找的。

# include <iostream>
# include <cstdio>
# include <cstring>
# include <queue>
# include <algorithm>
using namespace std;
int a[10001],b[10001],c[10001];

int lowbit(int s)
{
    return s&(-s);
}

void add(int i,int x)
{
    while(i<=10000){c[i]+=x;i+=lowbit(i);}
    return;
}

int sum(int i)
{
    int ans=0;
    while(i>0) {ans+=c[i];i-=lowbit(i);}
    return ans;
}

int search(int x)
{
    int L=1,R=10000,m;
    while(L<R)
    {
        m=(L+R)/2;
        if(sum(m)<x) L=m+1;
        else R=m;
    } 
    return L;
}

int main(void)
{
    int n,kase=0;
    while((scanf("%d",&n))!=EOF)
    {
        memset(c,0,sizeof(c));
        queue <int> q,fro;
        int cnt=0;
        for(int i=0;i<n;i++)
        {
            char s[10]; scanf("%s",s);
            if(s[0]=='i')
            {
                cnt++;
                scanf("%d",a+cnt);
                b[cnt]=a[cnt];
                q.push(1);
            }
            else if(s[0]=='q') q.push(0);
            else q.push(-1);
        }
        sort(b+1,b+1+cnt);
        int m=0,tem=0;
        printf("Case #%d:\n",++kase);
        while(!q.empty())
        {
            int ord=q.front();q.pop();
            if(ord==1)
            {
                tem++; m++;
                int x=lower_bound(b+1,b+cnt+1,a[tem])-b; 
                add(x,1); fro.push(x);
            }
            if(ord==0) printf("%d\n",b[search(m/2+1)]);
            if(ord==-1)
            {
                int x=fro.front(); fro.pop();
                add(x,-1); m--;
            }
        }
    }
    return 0;
}
Aguin

 

然而无意之间学习到了名为set大法的神奇玩意儿。

 

        set集合容器实现了红黑树(Red-Black Tree)的平衡二叉检索树的的数据结构,在插入元素时,它会自动调整二叉树的排列,把该元素放到适当的位置,以确保每个子树根节点的键值大于左子树所有节点的键值,而小于右子树所有节点的键值;另外,还得确保根节点的左子树的高度与有字数的高度相等,这样,二叉树的高度最小,从而检索速度最快。要注意的是,它不会重复插入相同键值的元素,而采取忽略处理。

        平衡二叉检索树的检索使用中序遍历算法,检索效率高于vector、deque、和list的容器。另外,采用中序遍历算法可将键值由小到大遍历出来,所以,可以理解为平衡二叉检索树在插入元素时,就会自动将元素按键值从小到大的顺序排列。

        构造set集合的主要目的是为了快速检索,使用set前,需要在程序头文件中包含声明“#include<set>”。

 

虽然不懂红黑树是什么。但是看起来好厉害的样子。忍不住抄了一个set大法。

(一直以来只知道用set来去重真是呵呵哒 迭代器什么的还是第一次用呢)

# include <iostream>
# include <cstdio>
# include <queue>
# include <set>
using namespace std;

int main(void)
{
    int n,kase=0;
    while((scanf("%d",&n))!=EOF)
    {
        printf("Case #%d:\n",++kase);
        queue <int> q;
        set <int> s1,s2;
        for(int i=0;i<n;i++)
        {
            char s[10]; scanf("%s",s);
            if(s[0]=='i')
            {
                int x; scanf("%d",&x);
                q.push(x);
                if(!s1.empty()&&x<*s1.rbegin())
                {
                    s1.insert(x);
                    if(s1.size()>s2.size()) {s2.insert(*s1.rbegin());s1.erase(*s1.rbegin());}    
                }
                else
                {
                    s2.insert(x);
                    if(s2.size()-s1.size()>1) {s1.insert(*s2.begin());s2.erase(*s2.begin());}
                } 
            }
            else if(s[0]=='q') printf("%d\n",*s2.begin());
            else
            {
                int x=q.front(); q.pop();
                if(s1.count(x))
                {
                    s1.erase(x);
                    if(s2.size()-s1.size()>1) {s1.insert(*s2.begin());s2.erase(*s2.begin());}
                }
                else 
                {
                    s2.erase(x);
                    if(s1.size()>s2.size()) {s2.insert(*s1.rbegin());s1.erase(*s1.rbegin());}
                }
            }
        }
    }
    return 0;
}
Aguin

 

2015年百度之星程序设计大赛 - 初赛(1) 1003 序列变换

感觉二分一直写不好。特别是收敛到边界的时候就弄错。

于是又写了一个不麻烦的二分+贪心。

然而并不知道为什么可以贪 - -b

# include <iostream>
# include <cstdio>
# include <cstring>
# include <algorithm>
using namespace std;
int N,a[100001],b[100001];

bool judge(int x)
{
    memcpy(b,a,sizeof(a));
    b[0]=b[0]-x;
    for(int i=1;i<N;i++)
    {
        if(b[i]>b[i-1]) b[i]=max(b[i-1]+1,b[i]-x);
        else if(b[i]+x>b[i-1]) b[i]=b[i-1]+1;
        else return false;
    }
    return true;
}

int main(void)
{
    int T;cin>>T;
    for(int kase=1;kase<=T;kase++)
    {
        scanf("%d",&N);
        for(int i=0;i<N;i++) scanf("%d",a+i);
        int L=0,R=1000000,mid;
        while(L<R)
        {
            mid=(L+R)/2;
            if(judge(mid)) R=mid;
            else L=mid+1;
        }
        printf("Case #%d:\n%d\n",kase,L);
    }
    return 0;
}
Aguin

 

前两周搞了会儿百度之星。虽然没出几个题并且早早的被淘汰了。

但是觉得偶尔打打这种。见见世面。也算有点帮助吧。

能补的稍微补了下。剩下的就不管了。

 

积分制取消了哈哈哈哈哈。

 

下周要考四级了。要考近代史了。

好!怕!怕!

posted @ 2015-05-31 00:02  Aguin  阅读(232)  评论(0编辑  收藏  举报