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;
}`