一些sb题(day1下)

来源:互联网 发布:做视频短片的软件 编辑:程序博客网 时间:2024/06/06 17:59

t1
有两副牌,每副牌都有n张。
对于第一副牌的每张牌长和宽分别是xi和yi。对于第二副牌的每张牌长和宽分别是aj和bj。第一副牌的第i张牌能覆盖第二副牌的第j张牌当且仅当xi>=aj并且yi>=bj。(注意牌不能翻转)当然一张牌只能去覆盖最多一张牌,而不能覆盖好多张。
LYK想让两副牌的各n张一一对应叠起来。它想知道第二副牌最多有几张能被第一副牌所覆盖。

这个题用贪心
对两副牌各自进行排序,然后贪心
枚举a,找a能覆盖的所有牌,去盖最接近的,为什么这样行呢
你的x是从小到大的,后面的牌只可能盖不到y,x一定能盖到
我是对y贪的,不对,因为不是所有牌都要盖。。
然后某些东西用平衡树维护。。

#include <stdio.h>#include <string.h>#include <algorithm>#include <iostream>#include <set>using namespace std;int n;multiset <int> s;struct node {int x,y;} a[100005],b[100005];int cmp(node i,node j) {return i.x<j.x;}int main(){    freopen("water.in","r",stdin);    freopen("water.out","w",stdout);    int T;    T=1;    while(T--)    {        scanf("%d",&n);        for(int i=0;i<n;i++) scanf("%d%d",&a[i].x,&a[i].y);        for(int i=0;i<n;i++) scanf("%d%d",&b[i].x,&b[i].y);        sort(a,a+n,cmp);        sort(b,b+n,cmp);        s.clear();        int k=0,ans=0;        for(int i=0;i<n;i++)        {            while(a[i].x>=b[k].x&&k<n)            {                 s.insert(b[k].y);                 k++;            }            if(s.empty())continue;            multiset<int>::iterator it=s.upper_bound(a[i].y);            if (it==s.begin()) continue; it--;            ans++; s.erase(it);        }        printf("%d\n",ans);    }    return 0;}

t2
题意
求最少有多少数能组成1~n的所有数
这个最少的就是用二进制组的,1 2 4 8一定能
方案就用dp
dp[i][j][k] 当前有i个金币,金币和是j,下一个金币。
第一层可以滚动掉

#include<cstdio>#include<cstring>#include<iostream>#include<cmath>int opt,n,ans,dp[2][1100][1100];int main(){    scanf("%d",&n);    int s=log(n)/log(2)+1;    printf("%d ",s);    dp[0][1][1]=1;    for(int i=1;i<s;i++) {        memset(dp[opt^1],0,sizeof dp[opt^1]);        for(int j=1;j<=n;j++)        for(int k=1;k<=n;k++)        if(dp[opt][j][k])        for(int q=k+1;q<=j+1;q++)        dp[opt^1][std::min(n,j+q)][q]+=dp[opt][j][k];        opt^=1;    }    for(int i=1;i<=n;i++) ans+=dp[opt][n][i];    printf("%d",ans);} 

t3
60
简单的动规。。

#include<cstdio>#include<iostream>#include<cstring>using namespace std;int dp[1100][21][1100],n,k,a[110000],s[1100][1100],ans=199999999;int main() {    freopen("dp.in","r",stdin);    freopen("dp.out","w",stdout);    scanf("%d%d",&n,&k);    for(int i=1;i<=n;i++) {        scanf("%d",&a[i]);        for(int j=1;j<=n;j++) s[i][j]=s[i-1][j];        s[i][a[i]]++;     }    memset(dp,127,sizeof dp);    dp[1][1][1]=0;    for(int i=1;i<=n;i++)    for(int j=1;j<=k;j++){        if(j<k){            for(int q=j-1;q<i;q++)          dp[i][j][q]=min(dp[i-1][j][q]+s[i-1][a[i]]-s[q-1][a[i]],dp[i][j][q]);        for(int q=j-1;q<i;q++)        dp[i][j+1][i]=min(dp[i-1][j][q],dp[i][j+1][i]);        }        else {            for(int q=j-1;q<i;q++)            dp[i][j][q]=min(dp[i-1][j][q]+s[i-1][a[i]]-s[q-1][a[i]],dp[i][j][q]);        }    }    for(int i=k;i<n;i++)     ans=min(ans,dp[n][k][i]);    printf("%d ",ans);}
正解`不会#include<iostream>#include<cstdio>using namespace std;const int N=100010;typedef long long LL;int c[N],a[N];LL f[N],g[N];int p,q,n,k;LL tot;void move(int l,int r)  // [p,q]之前的区间{    while (l<p) p--,tot+=c[a[p]],c[a[p]]++;    while (r>q) q++,tot+=c[a[q]],c[a[q]]++;    while (p<l) c[a[p]]--,tot-=c[a[p]],p++;    while (r<q) c[a[q]]--,tot-=c[a[q]],q--;}void work(int l,int r,int fl,int fr)//需要求dp[fl] ~ dp[fr]  最优解一定从l~r中的某一个转移过来{    if (fl>fr) return;    int mid=(fl+fr)>>1,mi;    LL mx=1LL<<60;    for (int i=l;i<=r;i++)    if (i<mid)    {        move(i+1,mid); -> tot=sum(i+1,mid);        if (f[i]+tot<mx) mx=f[i]+tot,mi=i;    }    g[mid]=mx;    work(l,mi,fl,mid-1);    work(mi,r,mid+1,fr);}int main(){    freopen("dp.in","r",stdin);    freopen("dp.out","w",stdout);    scanf("%d%d",&n,&k);    for (int i=1;i<=n;i++) scanf("%d",&a[i]);    f[0]=0;    for (int i=1;i<=n;i++) f[i]=1LL<<60;    while (k--)    {        p=1,q=0,tot=0;        for (int i=1;i<=n;i++) c[i]=0;        work(0,n-1,1,n);        for (int i=0;i<=n;i++) f[i]=g[i],g[i]=0;    }    cout<<f[n];    return 0;}`
原创粉丝点击