58测试贪心离散搜索LISdp

Posted qzgxlx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了58测试贪心离散搜索LISdp相关的知识,希望对你有一定的参考价值。

第一题 大天使之剑 大意:

  有n个怪,每个怪的ph 为 h[i],有三种攻击方式,普通攻击:一次打一个怪一滴血;重击(消耗1魔法值):一次打一个怪两滴血;群体攻击(消耗1魔法值):一次打所有怪一滴血。你有无数血,m个魔法值,每攻击一次怪后,还存活的所有怪会各攻击你一滴血。问你打完所有怪你最少被打了多少滴血。

解:

  看到这道题,首先想到的是搜索,一种一种的搜,把所有情况都搜出来找最小。在草稿纸上再列一些数据就会发现,其实是个贪心。在有魔法值的时候,尽量全用于群体攻击更划算,然后没有了就普通攻击。那重击呢?由于我的数据比较特殊,所以我判重击的条件是还剩两个偶数滴血的怪,但其实,不管它的血量是偶数还是奇数,重击都更划算。还有一些杂七杂八的减没减过sum的问题等,让我调试了一个下午。看来以后静态查错很重要,少犯小错误。代码写得丑。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define maxn 100005
 6 #define ll long long
 7 using namespace std;
 8 ll n,m,ph[maxn],ans,sum,cur=1;
 9 bool jian[maxn];
10 void print()
11 {
12     printf("%I64d",ans);
13     return ;
14 }
15 int main()
16 {
17     freopen("zhijian.in","r",stdin);
18     freopen("zhijian.out","w",stdout);
19     cin>>n>>m;
20     for (int i=1;i<=n;i++)
21       scanf("%d",&ph[i]);
22     sort(ph+1,ph+1+n);
23     while (m)
24     {
25         if (n-cur+1<=2){//改用重击
26             for (int i=cur;i<=n;i++)
27              if (!jian[i]) ph[i]-=sum;
28             while(m){
29                 if (cur>n)     {
30                     print();return 0;
31                 }
32                 if (ph[cur]<=2){
33                     ans+=n-cur;
34                     cur++;continue;
35                 }
36                 ph[cur]-=2;
37                 ans+=n-cur+1;
38                 m--;
39             }
40             while (cur<=n){
41                 if (ph[cur]){
42                     int ci=ph[cur]-1;
43                     ans+=(n-cur+1)*ci;
44                 }
45                 ans+=n-cur;
46                 cur++;
47             }
48             print();
49             return 0;
50         }
51         sum++;
52         ph[cur]--;int h=cur;
53         jian[cur]=true;
54         ans+=n-cur+1;
55         while (ph[cur]<=0){
56             ans--;
57             cur++;
58             ph[cur]-=sum;
59             jian[cur]=true;//判断 
60         }
61         m--;
62     }
63     while (cur<=n){
64         if (!jian[cur]) ph[cur]-=sum;//直接减会多减 
65         if (ph[cur]){
66             int ci=ph[cur]-1;
67             ans+=(n-cur+1)*ci;
68         }
69         ans+=n-cur;
70         cur++;
71     }
72     printf("%I64d",ans);
73     return 0;
74 }

第二题 保卫萝卜 大意:

  一个很大的矩阵,起点在正中心的方格。数据有向上下左右四个方向走的记录,输出走过的方格及所围的方格数。

解:

  有两种大体思路。一个是直接正着算面积,还有反着算走不到的点。我用的后者。但有一个问题,就是存矩阵。我把它走过的地方的最左边上面下面和右边记录下来,然后在这个包含它走的所有路的方格中从0,0开始遍历dfs,到不了的地方vis=false,即为ans++。注意要在搜索范围中再加一圈,因为可能走过的路把这个范围隔开了,就搜索不到。但这是60分的做法,100分做法要用离散化坐标的思想,先放一下。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define maxn 2005
 6 using namespace std;
 7 const int zl[2][4]={{0,0,1,-1},{1,-1,0,0}};
 8 int n,xi,yi,idx,sum,ans;
 9 bool mp[maxn][maxn],vis[maxn][maxn];
10 int uup,don,le,ri,stx,sty;
11 struct pp{
12     int x,y;
13 };
14 pp tur[1005];
15 char c[1005];
16 void dfs(int xx,int yy)
17 {
18     for (int i=0;i<=3;i++)
19     {
20         int ki=xx+zl[0][i],kj=yy+zl[1][i];
21         if (ki>=0&&kj>=0&&ki<=ri&&kj<=uup&&!vis[ki][kj]&&!mp[ki][kj])
22         {
23             vis[ki][kj]=true;
24             sum++;dfs(ki,kj);
25         }
26     }
27 }
28 int main()
29 {
30     freopen("luobo.in","r",stdin);
31     freopen("luobo.out","w",stdout);
32     cin>>n;
33     getchar();
34     for (int i=1;i<=n;i++)
35     {
36         c[i]=getchar();
37         getchar();int a;
38         scanf("%d",&a);
39         if (c[i]==L) {stx-=a;if (stx<le) le=stx;}
40         else if (c[i]==R){stx+=a;if (stx>ri) ri=stx;}
41         else if (c[i]==U) {sty+=a;if (sty>uup) uup=sty;}
42         else if (c[i]==D){sty-=a;if (sty<don) don=sty;}
43         tur[++idx].x=stx;tur[idx].y=sty;
44         getchar();
45     }
46     xi=-le+1;yi=-don+1;uup+=-don+2;ri+=-le+2;
47     mp[xi][yi]=true;
48     for (int i=1;i<=idx;i++)
49     {
50         tur[i].x+=-le+1;tur[i].y+=-don+1;
51         int a=min(xi,tur[i].x),b=max(xi,tur[i].x),ci=min(yi,tur[i].y),d=max(yi,tur[i].y);
52         for (int j=a;j<=b;j++)
53           for (int k=ci;k<=d;k++)
54             mp[j][k]=true;
55         xi=tur[i].x;yi=tur[i].y;
56     }
57     dfs(0,0);
58     for (int i=0;i<=ri;i++)
59       for (int j=0;j<=uup;j++)
60         if (!vis[i][j]) ans++;
61     printf("%d",ans);
62     return 0;
63 }

第三题 打地鼠 大意:

  (没错怎么都是游戏的名字)打地鼠,打的这个地鼠的肥胖值一定要比上一个打的大。地鼠最多出现t次,问最多能打多少地鼠。

解:

  看起来是个简单的最长上升序列。但是有一个t次,所以直接扫描加一个循环t就可以了,是不影响的。然后LIS 的nlogn的算法才能过这道题。具体的解释我觉得这个博客讲的就很清楚。http://blog.csdn.net/shuangde800/article/details/7474903   

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define maxn 100005
 6 using namespace std;
 7 int n,maxx,k,t,a[maxn],d[maxn],ans;
 8 int main()
 9 {
10     freopen("dishu.in","r",stdin);
11     freopen("dishu.out","w",stdout);
12     cin>>k>>n>>maxx>>t;
13     while (k--)
14     {
15         memset(d,0,sizeof(d));
16         int idx;ans=0;
17         for (int i=1;i<=n;i++)
18           scanf("%d",&a[i]);
19         d[1]=a[1];ans=1;
20         for(int i=1;i<=t;i++)
21           for (int j=1;j<=n;j++)
22           {
23               if (a[j]>d[ans]) d[++ans]=a[j];
24               else {
25                   int pos=lower_bound(d+1,d+1+ans,a[j])-d;//-d not -d-1 ?
26                   d[pos]=a[j];
27               }
28           }
29           printf("%d\n",ans);
30     }
31     return 0;
32 }


好好睡一觉,明天联考加油,不要有压力。

以上是关于58测试贪心离散搜索LISdp的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #650 (Div. 3) F1. Flying Sort (Easy Version) (离散化,贪心)

使用从循环内的代码片段中提取的函数避免代码冗余/计算开销

B1826 [JSOI2010]缓存交换 贪心+离散化+堆

Discrete Seekbar更改EditText大小

全文搜索用于提取文本片段(返回预期文本及其周围)

BZOJ 1852:[MexicoOI06]最长不下降序列(贪心+DP+线段树+离散化)