zoukankan      html  css  js  c++  java
  • 关于PJ 10.27

    题1 : Orchestra

    题意:

    给你一个 n*m 的矩阵,其中有一些点是被标记过的。

    现在让你求标记个数大于 k 个的二维区间个数。

    n、m 、k 最大是 10 。

    分析:

    part 1:

    10 的范围 ,直接暴力 $O(n^{6})$ 也能过,

    具体就是枚举区间的上边界、下边界、左边界、右边界,然后暴力累加这个区间内所有的标记点个数。

    代码不给出(因为比 part 2 的代码还长)。

    part 2:

    (考虑的是算法的优化,可以选择性看)

    我们可以考虑用矩阵前缀和优化。

    前缀和就是记录从开头到某个位置上所有值的和,这个大家应该都知道。

    那么二维其实就是记录从开头(一般是 ($1,1$))到某个位置(比如 ($i,j$))上所有值的和。

    这个可以看代码领会(其中 $val[i][j]$ 表示当前点是否被标记):

    1     for(int i=1;i<=n;++i) for(int j=1;j<=m;++j)
    2         mp[i][j]=val[i][j]+mp[i-1][j]+mp[i][j-1]-mp[i-1][j-1];

    这里 我们假设 $ mp[i-1,j],mp[i][j-1],mp[i-1][j-1] $ 已经处理好了,那么 $mp[i-1][j], mp[i][j-1], mp[i-1][j-1]$ 与 mp[i][j]  的关系如下:

    那么我们要求某个矩形区间的标记点个数的办法也是差不多的。

     比如要求出 u,l  到 d,r 这段区间 的标记点数量,那么答案就是: mp[d][r]+mp[u-1][l-1]-mp[u-1][r]-mp[d][l-1].

    代码如下:

     1 //by Judge
     2 #include<cstdio>
     3 #include<iostream>
     4 using namespace std;
     5 const int M=33;
     6 #ifndef Judge
     7 #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
     8 #endif
     9 char buf[1<<21],*p1=buf,*p2=buf;
    10 inline int read(){ int x=0,f=1; char c=getchar();
    11     for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    12     for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
    13 } int n,m,c,k,ans,mp[M][M];
    14 inline int check(int l,int r,int u,int d){
    15     return mp[d][r]+mp[u-1][l-1]-mp[u-1][r]-mp[d][l-1];
    16 }
    17 int main(){
    18     n=read(),m=read(),
    19     c=read(),k=read();
    20     for(int i=1,x,y;i<=c;++i)
    21         x=read(),y=read(),++mp[x][y];
    22     for(int i=1;i<=n;++i) for(int j=1;j<=m;++j)
    23         mp[i][j]+=mp[i-1][j]+mp[i][j-1]-mp[i-1][j-1];
    24     
    25     for(int u=1;u<=n;++u) for(int d=u;d<=n;++d)
    26         for(int l=1;l<=m;++l) for(int r=l;r<=m;++r)
    27             if(check(l,r,u,d)>=k) ++ans;
    28     
    29     return printf("%d
    ",ans),0;
    30 }

     part 3:

    (分析过度,不宜观看)

    这道题的数据有点小啊?如果说是100 的范围呢?(1000的话可能过大了,不过应该也不是没办法解)

    我们可以观察这区间之间的单调性:

    假设我们固定了边界:r、u、d 作为右边界、上边界和下边界,那么左边界越靠左,整个区间所会包含的标记点是单调不减的。

    然后这里就要用二分,如果你想知道具体内容的话就 Q 我吧(不要羞涩,撩就行了),我懒得写了。

    代码也不给出了(作者懒癌晚期)

    评价:

    大水题,应该拿满分。

    题2 : 质数

    题意:

    让你求一个区间范围内满足条件的数的个数,询问有多组。

    其中满足条件的数为:1.质数; 2.两个质数的乘积

    分析:

    只要你学过筛质数的话,这道题应该十分钟过的,又没什么套路。

    筛质数的话建议用欧拉筛法(关于欧拉,他非常牛皮,很多数论算法都是他发明的,可自行了解)

    题目没什么亮点,就是筛完质数后预处理一下前缀信息,询问的时候O(1) 回答就好了

    代码如下:

     1 //by Judge
     2 #include<cstdio>
     3 #include<iostream>
     4 #define ll long long
     5 using namespace std;
     6 const int M=1e7+11;
     7 const int MX=1e7;
     8 #ifndef Judge
     9 #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    10 #endif
    11 char buf[1<<21],*p1=buf,*p2=buf;
    12 inline int read(){ int x=0,f=1; char c=getchar();
    13     for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    14     for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
    15 } char sr[1<<21],z[20];int C=-1,Z;
    16 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
    17 inline void print(int x,char chr='
    '){
    18     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
    19     while(z[++Z]=x%10+48,x/=10);
    20     while(sr[++C]=z[Z],--Z);sr[++C]=chr;
    21 } int T,cnt,f[M],is[M],in[M],prim[M];
    22 inline void prep(){ is[1]=1;
    23     for(int i=2;i<=MX;++i){
    24         if(!is[i]) prim[++cnt]=i,in[i]|=1;
    25         for(int j=1;j<=cnt&&i*prim[j]<=MX;++j){
    26             is[i*prim[j]]|=1;
    27             if(!is[i]) in[i*prim[j]]|=1;
    28             if(i%prim[j]==0) break;
    29         }
    30     }
    31 }
    32 int main(){
    33     T=read(),prep();
    34     for(int i=1;i<=MX;++i)
    35         f[i]=f[i-1]+in[i];
    36     for(int l,r;T;--T)
    37         l=read(),r=read(),
    38         print(f[r]-f[l-1]);
    39     return Ot(),0;
    40 }

    评价:

     没什么难度的,最好 A 掉,起步 90 分(话说这题不卡常,基本只有 0 和 100 )

    题3 :Hanoi Factorys

    题意:

    几个空心环,让你依次叠高,要求下面的外径比上面的大,且内径下小上大,求最大高度。

    分析:

    这题有点鬼畜,还好之前打过直接 A 了。

    但其实没什么难的,首先维护外径单调递增,外径相同比较内径,内径大的放下面,

    为什么外径相同则内径大的放下面?

    因为这样能保证上面的环内径小,那么就能容纳外径更小的环。

    然后单调栈求解。

    想学单调栈的看看这篇博客(顺便可以把单调队列学了):click here

    然后刷一下这些题目就差不多会了:click here

     //by Judge
    1
    #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<vector> 5 #include<cstdio> 6 #include<cmath> 7 #include<queue> 8 #define P make_pair 9 #define ll long long 10 using namespace std; 11 const int M=1e6+100; 12 const int inf=1e9; 13 inline int read(){ 14 int x=0,f=1; char c=getchar(); 15 for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; 16 for(;isdigit(c);c=getchar()) x=x*10+c-'0'; 17 return x*f; 18 } 19 int n,head=1,tail; 20 priority_queue< pair<ll,ll> > q; 21 ll res=-inf; 22 struct Node{ 23 ll a,b,h; 24 friend bool operator < (const Node& x,const Node& y){ 25 return x.b!=y.b ? x.b>y.b : x.a>y.a; //b相同则先放a大的汉诺块 26 } 27 }p[M]; 28 29 int main(){ 30 n=read(); 31 for(int i=0;i<n;++i) 32 p[i].a=read(), 33 p[i].b=read(), 34 p[i].h=read(); 35 sort(p , p+n); 36 37 for(int i=0;i<n;++i){ 38 ll tmp=p[i].h; 39 while(!q.empty() && q.top().second>=p[i].b) 40 q.pop(); 41 if(!q.empty()) tmp+=q.top().first; 42 q.push(P(tmp,p[i].a)); 43 res=max(res , tmp); 44 } 45 cout<<res<<endl; 46 return 0; 47 }

    评价:

    没 A 掉?没关系,抓紧在剩下的时间提升自己,为战斗做准备,拿个 50+ 的暴力分差不多,最好当然是 A 掉。

     结论:

    OI 选手还是多学点算法的好。

    题4 :Distinct Paths

    题意:

    题意有点绕,就是让你求出一个矩阵中满足条件的方案数。

    条件是:对于从 1,1 到 n,m 的任意一条路径,使得路径上的点的颜色互不相同。

    难点在于:有些点的颜色已经给出。

    如果所有的点的颜色都不固定,这就是道数学题。

    分析:

    有点复杂,不会也正常(毕竟说实话我也没有解出来_(:з」∠)_)

    建议学会搜索以及简单的状压(不是状压dp,但是 状压 dp 这个东西学一下也行)

    首先你要发现题目的数据范围是假的。

    因为 k 很小,最大只有 10 ,只要 n+m-1 大于 k 了,那么必然不存在任意一种满足条件的方案。

    这点还是不难发现的。

    然后你不能太优秀。

    也就是不能一开始想的是 状压dp ,否则你就会陷入无休无止的修改状态表示以及思考状态转移之中。。。(好吧我就是这样耗了一个多小时)

    其次你要会搜索。

    这里搜索+剪枝才是本题正确打开方式。

    另外 noip 普及一般都有搜索题,而且爆搜适用于任何题目的骗分,如果加了剪枝或者记忆化之类的那就基本是正解

    最后你要会剪枝。

    这道题的亮点,各种鬼畜剪枝。

    搜索题,基本考的是剪枝,就算不考剪枝,大多也是可以用剪枝卡时间的。

    (卡时间真的非常重要,你怎么知道一个小小的剪枝会不会神奇让你分数过线?)

    代码如下:

     1 //by Judge
     2 #include<cstdio>
     3 #include<iostream>
     4 using namespace std;
     5 const int M=(1<<10)|3;
     6 const int mod=1e9+7;
     7 #ifndef Judge
     8 #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
     9 #endif
    10 char buf[1<<21],*p1=buf,*p2=buf;
    11 inline int read(){ int x=0,f=1; char c=getchar();
    12     for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    13     for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
    14 } int n,m,K,mp[13][13],cant[13][13],vis[13];
    15 inline void MOD(int& a){ if(a>mod) a-=mod; }
    16 #define lowbit(x) (x&-x)
    17 int dfs(int x,int y){
    18     if(y>m) y=1,++x;
    19     if(x>n) return 1;
    20     cant[x][y]=cant[x-1][y]|cant[x][y-1];
    21     int dx=x,dy=y+1,num=0;
    22     int S=cant[x][y],T=cant[x][y];
    23     while(S) S-=lowbit(S),++num;
    24     if(K-num<n+m-x-y+1) return 0;
    25     
    26     int ans=0,tmp=-1;
    27     for(int i=1;i<=K;++i){
    28         if((T>>i-1)&1) continue;
    29         if(!mp[x][y]||mp[x][y]==i){
    30             cant[x][y]=T|(1<<i-1),++vis[i];
    31             if(vis[i]==1) ans+=(tmp>=0?tmp:tmp=dfs(dx,dy));
    32             else ans+=dfs(dx,dy); MOD(ans),--vis[i];
    33         }
    34     } return ans;
    35 }
    36 int main(){
    37     n=read(),m=read(),K=read();
    38     if(n+m-1>K) return puts("0"),0;
    39     for(int i=1;i<=n;++i)
    40         for(int j=1;j<=m;++j){
    41             mp[i][j]=read();
    42             ++vis[mp[i][j]];
    43         }
    44     printf("%d
    ",dfs(1,1));
    45     return 0;
    46 }

    作为搜索 A 掉了去年普及第三题的 OI 选手,没有A掉这题,我只能说,老了。

    评价:

    略(guo)显(fen)毒瘤,拿个暴力分(这个好像没有)。。。额,能拿多少是多少,越多越好

    结论:

    搜索很重要!

    一等水平估计:

    240总有吧? (看在t4比较毒瘤的份上,不然肯定300+)

  • 相关阅读:
    第5.3课.多输入之多线程和fork
    第5.2课多输入之select
    第5.1课,多输入之轮询
    第4课.编写通用的Makefile
    第3课.电子书框架
    2.3freetype矢量字体
    建立u-boot,内核的SI工程
    2.1/2.2字符的编码方式及显示
    1.0数码相框框架分析
    [数据结构]一些有意思题目(一)
  • 原文地址:https://www.cnblogs.com/Judge/p/9861259.html
Copyright © 2011-2022 走看看