Contest_5 0614 By lhq

来源:互联网 发布:java中如何记录日志 编辑:程序博客网 时间:2024/06/06 03:15

转载请注明出处:http://blog.csdn.net/lhq_er/article/details/73604681
题目来源:学军中学NOIP2013提高组原创模拟题day2
https://wenku.baidu.com/view/3d053c4c76eeaeaad0f3309d.html###

Solution

T1 完全平方数 关键字:欧拉筛,快速幂,贪心

这道题目有两个区分点: 1.筛选素数的方法 2.计算结果的方法
1.处理方法显然就是欧拉筛(线性筛)了,注意要筛选到n/2,到sqrt(n)是不够的。
2.我们对任意一个数的阶乘进行质因数分解,例如:
15!=211 36 53 72 111 131
那么对于这些质因子我们能够取到的理论上的最大的完全平方数是210 36 52 72 110 130 即偶次幂完全取完,奇次幂减去1。事实上这事完全能够做到的,因为我们只要不取那个质数就能做到次数减一。
Tip:1.在求完质数后求n!中有几个质数p时可以用数学方法快速计算:
num=(n/p)+(n/p2)+(n/p3)+…… 这里的“/”都是下取整的
2.计算时要用到快速幂
3.一般的筛选法写得巧妙一点也可以过,如下:

//一般筛选法; int main(){    scanf("%lld",&n);    memset(vis,false,sizeof(vis)); vis[1]=true;    for (ll i=2;i<=n;i++)    {        if (!vis[i])         {            prime[++tot]=i;            for (ll j=i*i;j<=n;j+=i) vis[j]=true;        }    }

T2 卡片游戏 关键字:数学大力推一发,逆序对

上标解。
T2-1
T2-2

这道题ZJOI2017讲课时提到过,可惜没有记住怎么做,当然记住了也没用,因为当时讲的是Dancing Links,其实对种种小数据可以搜索+剪枝水过

这道题目的关键是我们要推出下面这个性质:所有的围栏都是互不相交的矩形
————————————————————证明————————————————————
首先,两个围栏互相包含的情况不可能在最优解中出现(把里面那个拆掉可以节省篱笆,得到一个更优解)。
其次,两个围栏相交的情况也一定不是最优,如下图所示,把重叠的部分拆掉可以得到更优解。
T3-1
由于我们的目标是最小化周长,可以得到这样一条重要性质:矩形的围栏比不规则形状的更优。如图,把里面的边往外平移,成为一个矩形的边框,这样可以在周长不变的情况下,围住更多的土地。(不用担心扩展出去的部分会和另外的围栏相交,因为这不可能在最优解中出现,刚才已经提到)
T3-2
有些情况下,矩形边框不仅扩大围住的范围而且能节省周长。
T3-3
所以,接下来我们只需考虑用矩形去包围兔子就够了。
T3-4
定义基本矩形或叫极小矩形——假如这个矩形再往里缩小一点就会有兔子从里面逃出。
T3-5
如就不是一个极小矩形,它可以往里收缩

现在它是一个极小矩形。
容易发现,最优解中必然只包含极小矩形。
——————————————————证毕————————————————————
解法一:
搜索+剪枝,枚举每一个兔子所在的栅栏,如果还可以再多一种栅栏就可以多一种选择:即开一个刚刚包围自己的栅栏。另一种选择就是和之前的某一个集合的兔子合并放到一个栅栏里,计算周长时找到上下左右的最大差值,记得+1。

解法二:
我们可以预处理出所有极小矩形:枚举所有兔子的非空子集,找出这个子集中最上、最左、最右、最下的兔子,就可得到一个极小矩形。(当然这样计算会出现许多重复的,剔除即可)。这种做法虽然是指数级的但是编码简单,而且n很小,仍可接受。
现在我们有了一堆矩形,对于每个矩形我们掌握它的两个属性:周长、围住了的兔子集合。问题转化为:从这堆矩形中选出不超过k个,在满足这些兔子集合互不相交,且其并集恰好是兔子全集的条件下,最小化总周长。
这是一个典型的精确覆盖问题,搜索解决即可。可以使用二进制来表示各个集合,用位运算的方法达到优化的效果。也可以用DLX来做,更快,更爽。 (我会告诉你我不会Dancing Links 吗,但不要慌,我会附上标程,可以借鉴一下)

总结:

这次考试T1没写出来欧拉筛,先优化版的一般筛法也没想到,只拿了70分,这提醒我要注意复习以前学过的知识,不要一直想着学新知识。T2也只拿了暴力分,数学推理都没敢去试一试,更没有想到是逆序对这种基础的知识,这也告诉了我们很多东西是伪装过的,不是你会逆序对就可以AC掉T2,还得有抽丝剥茧的能力。T3的dfs解法更是告诉了我们一样东西:暴力出奇迹。

CODE

T1

#include<bits/stdc++.h>using namespace std;#define ll long long#define MOD 100000007const ll MAXN=5000010,MAX_PRIME=350000;ll n,ans=1,tot;ll prime[MAX_PRIME];bool vis[MAXN];ll power(ll a,ll b,ll p){    ll ans=1;    while (b)    {        if (b&1) ans=(ans*a)%p;        a=(a*a)%p;        b>>=1;          }    return ans;}//欧拉筛; int main(){    scanf("%lld",&n);    memset(vis,false,sizeof(vis)); vis[1]=true;    for (ll i=2;i<=n;i++)    {        if (!vis[i]) prime[++tot]=i;        for (ll j=1;j<=tot && i*prime[j]<=n;j++)        {            vis[i*prime[j]]=true;            if (i%prime[j]==0) break;        }    }    for (ll i=1;i<=tot;i++)    {        ll t=n,a=prime[i],cnt=0;        while (t>0) t/=a,cnt+=t;        if (cnt>1)            if (cnt&1) ans=(ans*power(a,cnt-1,MOD))%MOD;            else ans=(ans*power(a,cnt,MOD))%MOD;    }    cout<<ans;    return 0;}

T2

#include<bits/stdc++.h>using namespace std;#define ll long longconst ll MAXN=500010;ll tmp[MAXN],A[MAXN],B[MAXN],ans;ll gcd(ll a,ll b){    if (b==0) return a;    else return gcd(b,a%b);}void Reverse_pair1(ll a[],ll b[],ll l,ll r){    if (l==r) return;    ll mid=(l+r)>>1;    Reverse_pair1(a,b,l,mid);    Reverse_pair1(a,b,mid+1,r);    ll i=l,j=mid+1,k=l;    while (i<=mid && j<=r)        if (a[i]<a[j])            b[k++]=a[i++];        else             b[k++]=a[j++],ans+=mid-i+1;    while (i<=mid) b[k++]=a[i++];    while (j<=r) b[k++]=a[j++];    for (ll i=l;i<=r;i++) a[i]=b[i];}void Reverse_pair2(ll a[],ll b[],ll l,ll r){    if (l==r) return;    ll mid=(l+r)>>1;    Reverse_pair2(a,b,l,mid);    Reverse_pair2(a,b,mid+1,r);    ll i=l,j=mid+1,k=l;    while (i<=mid && j<=r)        if (a[i]<=a[j])            b[k++]=a[i++];        else             b[k++]=a[j++],ans-=mid-i+1;    while (i<=mid) b[k++]=a[i++];    while (j<=r) b[k++]=a[j++];    for (ll i=l;i<=r;i++) a[i]=b[i];}int main(){    ll n,l,r,x,sum=0;    scanf("%lld%lld%lld",&n,&l,&r);    for (ll i=1;i<=n;i++)     {        scanf("%lld",&x);        sum=sum+x;        A[i]=l*i-sum;        B[i]=r*i-sum;    }    Reverse_pair1(A,tmp,0,n);    Reverse_pair2(B,tmp,0,n);    ll tot=n*(n+1)/2;    ll d=gcd(tot,ans);    if (ans==tot) cout<<"1";    else cout<<ans/d<<"/"<<tot/d;       return 0;}

T3

#include<bits/stdc++.h>using namespace std;#define ll long longconst int MAXN=16+1;int x[MAXN],y[MAXN],lx[MAXN],rx[MAXN],ly[MAXN],ry[MAXN],ans,n,m,maxk;void dfs(int t,int use,int tot){    if (tot>ans) return;    if (t>n)    {        ans=tot;        return;    }    if (use<maxk)    {        lx[use+1]=rx[use+1]=x[t];        ly[use+1]=ry[use+1]=y[t];        dfs(t+1,use+1,tot+4);        lx[use+1]=ly[use+1]=rx[use+1]=ry[use+1]=0;          }    for (int i=1;i<=use;i++)    {        int minx=lx[i],miny=ly[i],maxx=rx[i],maxy=ry[i];        int c=tot-2*((maxx-minx+1+maxy-miny+1));        lx[i]=min(lx[i],x[t]);  rx[i]=max(rx[i],x[t]);        ly[i]=min(ly[i],y[t]);  ry[i]=max(ry[i],y[t]);        c+=2*((rx[i]-lx[i]+1+ry[i]-ly[i]+1));        dfs(t+1,use,c);         lx[i]=minx; rx[i]=maxx; ly[i]=miny; ry[i]=maxy;     }}int main(){    scanf("%d%d%d",&m,&maxk,&n);    for (int i=1;i<=n;i++)        scanf("%d%d",&x[i],&y[i]);    ans=1<<30;    dfs(1,0,0);    cout<<ans;      return 0;}
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cstdlib>using namespace std;int m=0,n;int l,kmax;int X[25],Y[25],totX=0,totY=0;//离散化;int x[25],y[25];int L[500000],R[500000],U[500000],D[500000],C[500000];int head;int S[25]={0};int W[500000];int arr[500000]={0};int ans=30000;void remove(const int c) {      int i,j;         L[R[c]] = L[c];     R[L[c]] = R[c];     for (i = D[c]; i != c; i = D[i]) {              for (j = R[i]; j != i; j = R[j]) {                  U[D[j]] = U[j];                  D[U[j]] = D[j];                  S[C[j]]--;              }     }}void resume(const int c) {     int i,j;     for (i = U[c]; i != c; i = U[i]) {          for (j = L[i]; j != i; j = L[j]) {             S[C[j]]++;             U[D[j]] = j;             D[U[j]] = j;             }     }     L[R[c]] = c;     R[L[c]] = c; }void dfs(int k,int sum) {    int i,j,t;    int s=30000, c;    if(sum>=ans)return;    if (R[head] == head) {        ans=sum;       return;    }    if(k>=kmax)return;    for (t = R[head]; t != head; t = R[t]) {         if (S[t] < s) {            s = S[t];            c = t;            }   }   remove(c);   for (i = D[c]; i != c; i = D[i]) {       for (j = R[i]; j != i; j = R[j])            remove(C[j]);       dfs(k + 1,sum+W[i/n]);                        for (j = L[i]; j != i; j = L[j])            resume(C[j]);   }   resume(c);   return;}int main(){        scanf("%d%d%d",&l,&kmax,&n);    for (int i=0;i<n;i++)        scanf("%d%d",&x[i],&y[i]);        for (int i=1;i<1<<n;i++){        int l=5000,r=0,u=5000,d=0;        for (int j=0;j<n;j++)            if(i&(1<<j)){                         u=min(u,x[j]);                         d=max(d,x[j]);                         l=min(l,y[j]);                         r=max(r,y[j]);            }        bool ok=true;        for (int j=0;j<n && ok;j++)            if(!(i&(1<<j)) && x[j]>=u && x[j]<=d && y[j]>=l && y[j]<=r)ok=false;        if(!ok)continue;        W[++m]=(d-u+r-l+2)*2;        for (int j=0;j<n;j++)            if(i&(1<<j))arr[m*n+j]=1;    }    /////////////////////////////////    head=(m+1)*n;L[head]=R[head]=head;    L[0]=head;R[head]=0;R[n-1]=head;L[head]=n-1;    U[0]=D[0]=0;    for (int j=1;j<n;j++){        L[j]=j-1;        R[j-1]=j;        U[j]=D[j]=j;    }    for (int i=1;i<=m;i++){        int last=0;        int first;        for (int j=0;j<n;j++){            if (arr[i*n+j]){               if(last!=0){                           L[i*n+j]=last;                           R[i*n+j]=first;                           R[last]=i*n+j;                           last=i*n+j;               }               else {                    first=last=i*n+j;                    L[first]=R[first]=first;               }            }        }        if(last)L[first]=last;    }    for (int j=0;j<n;j++){        int last=j;        for (int i=1;i<=m;i++){            if(arr[i*n+j]){                           U[i*n+j]=last;                           D[i*n+j]=j;                           D[last]=i*n+j;                           last=i*n+j;                           C[i*n+j]=j;                           S[j]++;            }        }        U[j]=last;    }    dfs(0,0);//DLX    printf("%d\n",ans);    return 0;}
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 方舟mod订阅后怎么办 乡村mod遇到蜂巢怎么办 ubuntu完全卡死怎么办 win10以太网没了怎么办 hks泄压阀声音小怎么办 声卡驱动删除了怎么办 白色水彩没有了怎么办 大学毕业我想考军校怎么办? 考军校分数不够怎么办 大专工作不好找怎么办 小学二年级插班怎么办 进厂年龄不到怎么办 入伍批准书丢了怎么办 考驾照期间参军怎么办 学位房被占用怎么办 教室里回音太大怎么办 教室里味道太大怎么办 键盘只能打拼音怎么办 一师一优课件上传慢怎么办? 药店买药不给退怎么办 小孩热感冒发烧怎么办 孕妇热感冒了怎么办 孕妇热感冒喉咙痛怎么办 空军一号有划痕怎么办 高铁上乘客太吵怎么办 军官礼服丢了怎么办 空军大檐帽帽袋坏了怎么办 保安不发工资怎么办 做保安工资不资不发怎么办 公安改革辅警怎么办 皮带带子丢了怎么办 警校学生证丢了怎么办 警校证丢了怎么办 盘查没带身份证怎么办 网线拔不出来怎么办 车间压强差过大怎么办 不遵守交通规则交警怎么办 西裤屁股磨出光该怎么办 中暑发烧不退烧怎么办 小孩中暑反复发烧怎么办 上火导致的发烧怎么办