T1 水题(water)

Time Limit:1000ms   Memory Limit:128MB

题目描述

LYK出了道水题。

这个水题是这样的:有两副牌,每副牌都有n张。

对于第一副牌的每张牌长和宽分别是xi和yi。对于第二副牌的每张牌长和宽分别是aj和bj。第一副牌的第i张牌能覆盖第二副牌的第j张牌当且仅当xi>=aj并且yi>=bj。(注意牌不能翻转)当然一张牌只能去覆盖最多一张牌,而不能覆盖好多张。

LYK想让两副牌的各n张一一对应叠起来。它想知道第二副牌最多有几张能被第一副牌所覆盖。

输入格式(water.in)

第一行一个数n。

接下来n行,每行两个数xi,yi。

接下来n行,每行两个数aj,bj。

输出格式(water.out)

输出一个数表示答案。

输入样例

3

2 3

5 7

6 8

4 1

2 5

3 4

输出样例

2

数据范围

对于50%的数据n<=10。

对于80%的数据n<=1000。

对于100%的数据1<=n<=100000,1<=xi,yi,aj,bj<=10^9。

 #include <algorithm>
#include <cstdio> inline void read(int &x)
{
x=; register char ch=getchar();
for(; ch>''||ch<''; ) ch=getchar();
for(; ch>=''&&ch<=''; ch=getchar()) x=x*+ch-'';
}
const int N();
int n,ans;
struct Node {
int x,y;
bool operator < (const Node&z)const
{
if(x==z.x) return y<z.y;
return x<z.x;
}
}a[N],b[N];
const int M();
int vis[M][M],sumvis;
int link[M][M],mat[M]; bool find(int u)
{
for(int v=; v<=n; ++v)
if(link[u][v]&&vis[u][v]!=sumvis)
{
vis[u][v]=sumvis;
if(!mat[v]||find(mat[v]))
{
mat[v]=u;
return ;
}
}
return ;
} inline void violence()
{
for(int i=; i<=n; ++i)
for(int j=; j<=n; ++j)
link[i][j]=(a[i].x>=b[j].x&&a[i].y>=b[j].y);
for(int i=; i<=n; ++i)
{
sumvis++;
if(find(i)) ans++;
}
printf("%d\n",ans);
} int Presist()
{
// freopen("1.txt","r",stdin);
freopen("water.in","r",stdin);
freopen("water.out","w",stdout);
read(n);
for(int i=; i<=n; ++i)
read(a[i].x),read(a[i].y);
for(int i=; i<=n; ++i)
read(b[i].x),read(b[i].y);
if(n<=) violence();
return ;
} int Aptal=Presist();
int main(int argc,char**argv){;}

匈牙利,60分

因为可能存在 xi,yi=1,,,xj==1,yj,的情况,这种情况下,无法确定怎样覆盖更优,

所以可以以xi从小到大排序,在满足xi的情况下,将B组的y放到某数据结构中,再找满足A组的y的最大的y

需要有插入,删除不超过y的最大数的数据结构,数组80,muliset/平衡树/权值线段树

 #include <algorithm>
#include <cstdio>
#include <set> inline void read(int &x)
{
x=; register char ch=getchar();
for(; ch>''||ch<''; ) ch=getchar();
for(; ch>=''&&ch<=''; ch=getchar()) x=x*+ch-'';
}
const int N(); std:: multiset<int>set_; struct Card {
int x,y;
bool operator < (const Card&c)const
{
return x<c.x;
}
}a[N],b[N]; int Presist()
{
freopen("water.in","r",stdin);
freopen("water.out","w",stdout);
int n,ans=; read(n);
for(int i=; i<=n; ++i)
read(a[i].x),read(a[i].y);
for(int i=; i<=n; ++i)
read(b[i].x),read(b[i].y);
std:: sort(a+,a+n+);
std:: sort(b+,b+n+);
for(int i=,j=; i<=n; ++i)
{
for(; a[i].x>=b[j].x&&j<=n; )
set_.insert(b[j].y),++j;
if(set_.empty()) continue;
std:: multiset<int>:: iterator it=set_.upper_bound(a[i].y);
if(it==set_.begin()) continue;
else ans++,set_.erase(--it);
}
printf("%d\n",ans);
return ;
} int Aptal=Presist();
int main(int argc,char**argv){;}

AC

T2 梦境(dream)

Time Limit:1000ms   Memory Limit:128MB

题目描述

LYK做了一个梦。

这个梦是这样的,LYK是一个财主,有一个仆人在为LYK打工。

不幸的是,又到了月末,到了给仆人发工资的时间。但这个仆人很奇怪,它可能想要至少x块钱,并且当LYK凑不出恰好x块钱时,它不会找零钱给LYK。

LYK知道这个x一定是1~n之间的正整数。当然抠门的LYK只想付给它的仆人恰好x块钱。但LYK只有若干的金币,每个金币都价值一定数量的钱(注意任意两枚金币所代表的钱一定是不同的,且这个钱的个数一定是正整数)。LYK想带最少的金币,使得对于任意x,都能恰好拼出这么多钱。并且LYK想知道有多少携带金币的方案总数。

具体可以看样例。

输入格式(dream.in)

第一行一个数n,如题意所示。

输出格式(dream.out)

输出两个数,第一个数表示LYK至少携带的金币个数,第二数表示方案总数。

输入样例

6

输出样例

3 2

样例解释

LYK需要至少带3枚金币,有两种方案,分别是{1,2,3},{1,2,4}来恰好得到任意的1~n之间的x。

输入样例2

10

输出样例2

4 8

数据范围

对于30%的数据n<=10。

对于60%的数据n<=100。

对于100%的数据n<=1000。

 #include <algorithm>
#include <cstdio> #define min(a,b) (a<b?a:b) inline void read(int &x)
{
x=; register char ch=getchar();
for(; ch>''||ch<''; ) ch=getchar();
for(; ch>=''&&ch<=''; ch=getchar()) x=x*+ch-'';
}
const int N();
int n,ans,count;
bool vis[N];
int a[N]; void DFS(int num,int cnt,int sum)
{
if(sum>=n) { ans++; return ; }
if(cnt>count) { return ; }
for(int i=num+; i<=min(a[cnt+],sum+); ++i)
{
if(vis[i]) continue; vis[i]=;
DFS(i,cnt+,sum+i); vis[i]=;
}
} int Presist()
{
// freopen("1.txt","r",stdin);
freopen("dream.in","r",stdin);
freopen("dream.out","w",stdout);
read(n);
for(int sum=; sum<n; ++sum)
a[++count]=sum+,sum<<=;
DFS(,,);
printf("%d %d\n",count,ans);
return ;
} int Aptal=Presist();
int main(int argc,char**argv){;}

爆搜30

方案总数:dp,搜索

2^0+2^1+...+2^k = O(n)  k=log(n)

dfs(Max,Sum,S) // Max金币最大值,Sum所有金币的和,S金币的数量

dp[i][j][k] 当前有i个金币,金币和是j,最大的金币k。

if (dp[i][j][k]) 枚举下一枚金币是啥。

 #include <cstdio>

 #define min(a,b) (a<b?a:b)

 inline void read(int &x)
{
x=; register char ch=getchar();
for(; ch>''||ch<''; ) ch=getchar();
for(; ch>=''&&ch<=''; ch=getchar()) x=x*+ch-'';
}
int n,cnt,ans,f[][][]; int Presist()
{
freopen("dream.in","r",stdin);
freopen("dream.out","w",stdout); read(n);
for(; (<<cnt)<=n; ) cnt++;
f[][][]=;
for(int i=; i<cnt; ++i)
for(int j=; j<=n; ++j)
for(int k=; k<=n; ++k)
{
if(!f[i][j][k]) continue;
for(int p=k+; p<=j+; ++p)
f[i+][min(j+p,n)][p]+=f[i][j][k];
}
for(int i=; i<=n; ++i) ans+=f[cnt][n][i];
printf("%d %d\n",cnt,ans);
return ;
} int Aptal=Presist();
int main(int argc,char**argv){;}

AC

T3 动态规划(dp)

Time Limit:1000ms   Memory Limit:128MB

题目描述

LYK在学习dp,有一天它看到了一道关于dp的题目。

这个题目是这个样子的:一开始有n个数,一段区间的价值为这段区间相同的数的对数。我们想把这n个数切成恰好k段区间。之后这n个数的价值为这k段区间的价值和。我们想让最终这n个数的价值和尽可能少。

例如6个数1,1,2,2,3,3要切成3段,一个好方法是切成[1],[1,2],[2,3,3],这样只有第三个区间有1的价值。因此这6个数的价值为1。

LYK并不会做,丢给了你。

输入格式(dp.in)

第一行两个数n,k。

接下来一行n个数ai表示这n个数。

输出格式(dp.out)

一个数表示答案。

输入样例

10 2

1 2 1 2 1 2 1 2 1 2

输出样例

8

数据范围

对于30%的数据n<=10。

对于60%的数据n<=1000。

对于100%的数据1<=n<=100000,1<=k<=min(n,20),1<=ai<=n。

其中有30%的数据满足ai完全相同均匀分布在所有数据中。

dp[i][j] 1~i 切了j刀,的最优解

dp[i][j]=min{dp[k][j-1]+sum(k+1,i)}

这个k是从大到小进行枚举,每次枚举时更新这个sum 20*n^2  60分

 #include <cstring>
#include <cstdio> #define min(a,b) (a<b?a:b)
#define LL long long inline void read(int &x)
{
x=; register char ch=getchar();
for(; ch>''||ch<''; ) ch=getchar();
for(; ch>=''&&ch<=''; ch=getchar()) x=x*+ch-'';
}
const int N();
int a[N],cnt[N],L,R;
int sum[][];
LL f[][]; int Presist()
{
freopen("dp.in","r",stdin);
freopen("dp.out","w",stdout); int n,k; read(n),read(k);
for(int i=; i<=n; ++i) read(a[i]);
for(int i=; i<=n; ++i)
{
++cnt[a[i]];
for(int j=i+; j<=n; ++j)
sum[i][j]=sum[i][j-]+cnt[a[j]],++cnt[a[j]];
memset(cnt,,sizeof(cnt));
}
for(int i=; i<=n; ++i)
for(int j=; j<=k; ++k)
f[i][j]=0x7fffffff;
for(int i=; i<=n; ++i)
{
f[i][]=sum[][i];
for(int j=; j<=min(i,k); ++j)
for(int t=; t<i; ++t)
f[i][j]=min(f[i][j],f[t][j-]+sum[t+][i]);
}
printf("%d\n",f[n][k]);
return ;
} int Aptal=Presist();
int main(int argc,char**argv){;}

固定j,随着i的增大,k不会减少

20*n^2的简单dp -> 在固定j的情况下 随着i的增大,k不降 -> 分治求dp值

 #include <cstring>
#include <cstdio> #define LL long long inline void read(int &x)
{
x=; register char ch=getchar();
for(; ch>''||ch<''; ) ch=getchar();
for(; ch>=''&&ch<=''; ch=getchar()) x=x*+ch-'';
}
const int N();
int a[N],cnt[N],L,R;
LL f[N],g[N],sum; inline void move(int l,int r)
{
for(; L>l; ) sum+=cnt[a[--L]]++;
for(; L<l; ) sum-=--cnt[a[L++]];
for(; R>r; ) sum-=--cnt[a[R--]];
for(; R<r; ) sum+=cnt[a[++R]]++;
} void work(int u,int v,int l,int r)
{
if(l>r) return ;
int mid=l+r>>,pos;
LL minn=0x7fffffff;
for(int i=u; i<mid&&i<=v; ++i)
{
move(i+,mid);
if(sum+f[i]<minn)
minn=sum+f[i],pos=i;
}
g[mid]=minn;
work(u,pos,l,mid-);
work(pos,v,mid+,r);
} int Presist()
{
freopen("dp.in","r",stdin);
freopen("dp.out","w",stdout); int n,k; read(n),read(k);
for(int i=; i<=n; ++i) read(a[i]);
for(int i=; i<=n; ++i) f[i]=0x7fffffff;
for(; k--; )
{
memset(cnt,,sizeof(cnt));
L=,R=,sum=,work(,n-,,n);
for(int i=; i<=n; ++i) f[i]=g[i],g[i]=;
}
printf("%lld\n",f[n]);
return ;
} int Aptal=Presist();
int main(int argc,char**argv){;}

AC

2017-10-28-afternoon-清北模拟赛的更多相关文章

  1. 2017.10.1 国庆清北 D1T1 zhx的字符串题

    题目背景 2017国庆清北D1T1 题目描述 你是能看到第一题的 friends 呢. ——hja 何大爷对字符串十分有研究,于是天天出字符串题虐杀 zhx.何大爷今天为 字符串定义了新的权值计算方法 ...

  2. 2017.10.3北京清北综合强化班DAY3

    括号序列(bracket) Time Limit:1000ms   Memory Limit:128MB 题目描述 LYK有一个括号序列,但这个序列不一定合法. 一个合法的括号序列如下: ()是合法的 ...

  3. 2017.10.4北京清北综合强化班DAY4

    财富(treasure) Time Limit:1000ms   Memory Limit:128MB 题目描述 LYK有n个小伙伴.每个小伙伴有一个身高hi. 这个游戏是这样的,LYK生活的环境是以 ...

  4. 2017.10.7北京清北综合强化班DAY7

    1.计数 (count.cpp/c/pas) 时间限制:1s 内存限制:256MB [问题描述] 给出m个数a[1],a[2],…,a[m] 求1~n中有多少数不是a[1],a[2],…,a[m]的倍 ...

  5. 2017.10.6北京清北综合强化班DAY6

    题目大意:改变一个数的位置 把一个序列变成不下降序列 题解: 设置一个pre,如果破坏单调性,就把‘删除’这个.否则把pre修改为当前元素的值. 考试时这样得了90分,是因为我的做法只能过这样的数据 ...

  6. 2017.10.5北京清北综合强化班DAY5

    拼不出的数lost.in/.out/.cpp[问题描述]3 个元素的集合{5, 1,2} 的所有子集的和分别是0,1, 2, 3, 5, 6, 7, 8.发现最小的不能由该集合子集拼出的数字是4.现在 ...

  7. 2017.10.1北京清北综合强化班DAY1

    a[问题描述]你是能看到第一题的 friends 呢.——hja何大爷对字符串十分有研究,于是天天出字符串题虐杀 zhx. 何大爷今天为字符串定义了新的权值计算方法.一个字符串 由小写字母组成,字符串 ...

  8. 2017.10.4 国庆清北 D4T2 正方形

    题目描述 在一个10000*10000的二维平面上,有n颗糖果. LYK喜欢吃糖果!并且它给自己立了规定,一定要吃其中的至少C颗糖果! 事与愿违,LYK只被允许圈出一个正方形,它只能吃在正方形里面的糖 ...

  9. 2017.10.6 国庆清北 D6T2 同余方程组

    题目描述 求关于x 的同余方程组 x%a1 = b1 x%a2 = b2 x%a3 = b3 x%a4 = b4 的大于等于0 的最小整数解. 输入输出格式 输入格式: 一行8 个整数,表示a1; b ...

  10. 2017.10.6 国庆清北 D6T1 排序

    题目描述 小Z 有一个数字序列a1; a2; .... ; an,长度为n,小Z 只有一个操作:选 定p(1<p<n),然后把ap 从序列中拿出,然后再插⼊到序列中任意位置. 比如a 序列 ...

随机推荐

  1. Luogu P2397 yyy loves Maths VI (mode)

    题目传送门 虽然只是一道黄题,但还是学到了一点新知识-- 摩尔投票法 用\(O(1)\)的内存,\(O(n)\)的时间来找出一串长度为n的数中的众数,前提是众数出现的次数要大于\(n/2\) 方法很简 ...

  2. 【转】Java重构-策略模式、状态模式、卫语句

    前言 当代码中出现多重if-else语句或者switch语句时.弊端之一:如果这样的代码出现在多处,那么一旦出现需求变更,就需要把所有地方的if-else或者switch代码进行更改,要是遗漏了某一处 ...

  3. Sql语句的一些事(一)

    (1)LIMIT子句(MySql) ----LIMIT 子句用于规定要返回的记录的数目,一般和Order By一起使用 经常用于数据的分页查询,但是一旦数据量一大,limit的性能就会急速下降 格式: ...

  4. DNS服务-主从架构搭建

    为了网站的可靠性,通常都会有多个DNS服务器,万一DNS服务器宕机了,可以实现DNS服务器容错 通常都会有一个主DNS服务器,后面配若干个辅助DNS服务器,这个主DNS服务器的数据库会同步给其他的DN ...

  5. RN笔记

    https://facebook.github.io/react-native/docs/using-a-listview.html react native类似于react,不过它使用的是原生组件, ...

  6. 浏览器中如何获取想要的offsetwidth、、、clientwidth、、offsetheight、、、clientheight。。。

    clientWidth是对象看到的宽度(不含边线,即border)scrollWidth是对象实际内容的宽度(若无padding,那就是边框之间距离,如有padding,就是左padding和右pad ...

  7. python 学习总结4

    数字类型及操作 一.整数类型 (1)python中的整数与数学中的概念是一致的,可以正也可以负,没有取值范围.   pow(x,y)函数是计算x的y次幂,想计算多大就多大. (2)在整数类型中有四种进 ...

  8. teatime、

    Python之路,Day7 - 面向对象编程进阶   本节内容: 面向对象高级语法部分 经典类vs新式类 静态方法.类方法.属性方法 类的特殊方法 反射 异常处理 Socket开发基础 作业:开发一个 ...

  9. Python9-内置函数2-day16

    #zip方法 l = [1,2,3] l2 = ['a','b','c'] l3 = ('*','**',[1,2]) l4 = {'k1':1,'k2':2} for i in zip(l,l2,l ...

  10. POJ 1849 树的直径 Two

    如果一个点开始遍历一棵树再回到原点那么每条边走两次. 现在是两个人从同一点出发,那么最后遍历完以后两人离得越远越好. 最后两人所处位置的路径上的边走了一次,其他边走了两次. 要使总路程最小,两人最后停 ...