【杂题1】USACO 2018 Open Contest-练习
https://www.xoj.red/contests/show/1231
下面会写一些题目的解析什么的,当然不会粘贴题目只是简单提一下
(部分题目简单的题目就不概括了)
其实难度应该前面比较低.
本题求出冒泡排序需要几趟。
考虑一次冒泡排序的交换,减小对应1个位子上的1个逆序对。
但是对于每一个位子所需要减小的逆序对数量是不一样的。
对于每一趟,消去每一个位子上1个逆序对
所以趟数就是每个位子上的数产生逆序对数的最大值。
最后的+1指的是即使上一次已经消除所有逆序对了,我们并不知道数组有序了,所以判断最后一遍查看是否有序。
考虑树状数组维护$O(n log_2 n)$
和善的树状数组代码如下:
# include <bits/stdc++.h>
using namespace std;
const int N=1e5+;
int a[N],tmp[N],c[N];
int n,T;
void update(int x){for (;x<=n;x+=x&-x)c[x]++;}
int query(int x){int ret=;for (;x;x-=x&-x) ret+=c[x];return ret;}
int main()
{
scanf("%d",&n); tmp[]=n;
for (int i=;i<=n;i++) scanf("%d",&a[i]),tmp[i]=a[i];
sort(tmp+,tmp+tmp[]+);
T=unique(tmp+,tmp++tmp[])-tmp-;
int ans=;
for (int i=;i<=n;i++) {
int w=lower_bound(tmp+,tmp++T,a[i])-tmp;
update(w);
ans=max(i-query(w),ans);
}
printf("%d\n",ans+);
return ;
}
问题A: 3894: Out of Sorts
考虑一个简单的贪心,每次选择当前等待奶牛数目最多的一个,占用等待奶牛数少的奶牛的位置。
如果不是这样做,对答案会有正贡献,是我们不期望的,与答案最优性矛盾,我们选择一个一定是最优的决策。
# include <bits/stdc++.h>
using namespace std;
const int N=1e5+;
int n,a[N];
int main()
{
scanf("%d",&n);
for (int i=;i<=n;i++) scanf("%d",&a[i]);
sort(a+,a++n);
int cnt=,Ans=;
for (int i=n;i>=;i--) {
if (cnt<=a[i])Ans++,cnt++;
else break;
}
printf("%d\n",Ans);
return ;
}
问题B: 3895: Lemonade Line
大概是不存在一个正解的。
考虑这样一个事情,如果正反来了一边那么每一次对于i位置上的数a[i]来说他左边位置j $\in $ [1,i-1]比a[i]严格大的数有一个被放到了i的右边
他右边的位置j$\in $ [i+1,n]比a[i]严格小的数有一个被放到了i的左边。当且仅当a[i]左边和右边不存在上述的数那么停止。
如果把一个数组变为有序显然第i个位子上放置第i大的数。
显然他们的位置一定在i位置后面。所有至少需要移动这么多次,把每一个比i大的数移动到i的右面。
显然我们冒泡1次对于每个i对应的有多少数在他左边只能减少1个这样的数,所以答案就是max{前i个数里面有多少个数字离散化后是比i大的,1}
# include <bits/stdc++.h>
using namespace std;
const int N=1e5+;
int c[N],n;
struct rec{int x,id;}a[N];
bool cmp(rec a,rec b)
{
if (a.x!=b.x) return a.x<b.x;
return a.id<b.id;
}
void update(int x){for (;x<=n;x+=x&-x) c[x]++;}
int query(int x){int ret=; for (;x;x-=x&-x) ret+=c[x]; return ret;}
int main()
{
scanf("%d",&n);
for (int i=;i<=n;i++)
scanf("%d",&a[i].x),a[i].id=i;
sort(a+,a++n,cmp);
int ans=;
for (int i=;i<=n;i++){
update(a[i].id);
ans=max(ans,i-query(i));
}
printf("%d\n",ans);
return ;
}
问题D: 3897: Out of Sorts
本题要求最大化pos满足前面若干条边连起来是一个无环图。
求最优遍历顺序,想到拓扑排序check+二分答案,然后手打堆优化STL常数。
先存输入,每一次二分答案位置pos,把前面pos个连边系统前面连到后面,然后跑拓扑,每次选择入度为0,标号最小的一个遍历
这里用到heap了,然后使用priority_queue在不开O2情况下TLE,然后就写了一个手写堆。
# include <bits/stdc++.h>
using namespace std;
const int N=1e5+,M=2e5+;
int head[N],ind[N],ans[N];
bool vis[N];
vector<int>ipt[N];
int n,m,tot;
struct rec{int pre,to;}a[M];
inline int read()
{
int X=,w=; char c=;
while(c<''||c>'') {w|=c=='-';c=getchar();}
while(c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
return w?-X:X;
}
inline void write(int x)
{
if (x>) write(x/);
putchar(''+x%);
}
void adde(int u,int v)
{
ind[v]++;
a[++tot].pre=head[u];
a[tot].to=v;
head[u]=tot;
}
struct heap{
# define lson (x<<)
# define rson ((x<<)+)
# define fath (x>>)
int Size,c[N<<];
heap(){Size=;}
void down(int x) {
while (x<Size) {
if (lson>Size) break;
int t=lson;
if (rson<=Size&&c[rson]<c[lson]) t=rson;
if (c[x]<=c[t]) break;
swap(c[x],c[t]);
x=t;
}
}
void up(int x) {
while (x) {
if (c[x]>c[fath]) break;
swap(c[x],c[fath]);
x=fath;
}
}
int top(){return c[];}
void push(int x){c[++Size]=x;up(Size);}
void pop() {swap(c[],c[Size--]);down();}
bool empty(){ return !Size;}
}q;
bool check(int Mid)
{
tot=;
memset(vis,false,sizeof(vis));
memset(head,,sizeof(head));
memset(ind,,sizeof(ind));
for (int i=;i<=Mid;i++)
for (int j=;j<ipt[i].size();j++)
adde(ipt[i][j-],ipt[i][j]);
for (int i=;i<=n;i++)
if (ind[i]==) q.push(i);
ans[]=;
while (!q.empty()) {
int u=q.top(); q.pop();
vis[u]=true;
ans[++ans[]]=u;
for (int i=head[u];i;i=a[i].pre){
int v=a[i].to;
if (ind[v]==) return false;
ind[v]--;
if (ind[v]==) q.push(v);
}
}
for (int i=;i<=n;i++)
if (!vis[i]) return false;
return true;
}
int main()
{
n=read();m=read();
for (int i=;i<=m;i++) {
int r=read();
for (int j=;j<=r;j++) {
int t=read();
ipt[i].push_back(t);
}
}
int L=,R=m,Ans=;
while (L<=R) {
int mid=(L+R)>>;
if (check(mid)) Ans=mid,L=mid+;
else R=mid-;
}
if (Ans==) {
for (int i=;i<=n;i++) write(i),putchar(' ');
putchar('\n');
return ;
}
check(Ans);
for (int i=;i<=n;i++) write(ans[i]),putchar(' ');
putchar('\n');
return ;
}
问题E: 3898: Milking Order
考虑01分数规划,即二分答案套dp检查。
设答案$x\leq \frac{\sum w_i}{\sum t_i} $移项可得$\sum t_i - x \sum w_i \geq 0$
即要求我们对于给定参数x,求一组$w_i$和$t_i$满足$\sum t_i - x \sum w_i \geq 0$
即$max\{ \sum t_i - x \sum w_i \} \geq 0$
对于第i头奶牛的贡献就变成一个确定的数了,即$t_i-xw_i$
考虑01背包。
设f[x]表示当前选择总重量为x,$\sum t_i - x \sum w_i $的最大值。
考虑从x转移出去对x+w[i]有影响,有转移方程$f[x+w[i]]=max(f[x+w[i]],f[x]+t_i-xw_i)$
然后要求总重量超过W,事实上我们并不关心到底超过W多少,只要超过就行,那么就统计在恰好的地方
即统计在f[W]处,那么f[W]就是答案。
# include <bits/stdc++.h>
# define inf (<<)
using namespace std;
const int N=1e5+;
double f[N];
int w[N],t[N];
int n,W;
bool check(double x)
{
f[]=;
for(int i=;i<=W;i++) f[i]=-inf;
for (int i=;i<=n;i++)
for (int j=W;j>=;j--)
f[min(j+w[i],W)]=max(f[min(j+w[i],W)],f[j]+t[i]-x*w[i]);
return f[W]>=0.0;
}
int main()
{
scanf("%d%d",&n,&W);
for (int i=;i<=n;i++)
scanf("%d%d",&w[i],&t[i]);
double l=,r=inf,ans;
while (r-l>=(1e-)){
double mid=(l+r)/2.0;
if (check(mid)) ans=mid,l=mid;
else r=mid;
}
ans=ans*;
printf("%d\n",(int)ans);
return ;
}
问题F: 3899: Talent Show
我们不妨宏观考虑这个排序的问题,在对于A进行子冒泡排序的时候,可以发现,比第i个元素小的元素且在i右边的元素是以1贡献/次向i移动的。
所以第i个元素和第i+1元素之间的隔板产生的区间长度就是$ (maxpos-i+1-1)=maxpos-i $,其中$ maxpos $指的是排序以后比$a_i$元素更小的,但排在$a_i$元素的右边,且距离$a_i$最远的数$a_j$的下标(位置)$j$。
对于i被计算1次当他的前面隔板不是连续的,或者 后面隔板不是连续的满足其一即可,所以若把i存在于的这个隔板不连续的区间排成有序,那么仅对于元素i它被算的次数(产生的贡献)是$max(t_{i-1},t_i)$
说明一下: 如果i前后隔板都不连续的话i被产生$max(t_{i-1},t_i)$后便不产生贡献了,如果前面或后面隔板不连续显然。
有了上面的说明,这个题目的算法呼之欲出,
1. 遍历原数组,当前位置为i,求出$ t_i $,查找最后一个比$a_i$小的数出现的位置为j,令$ t_i = j - i $
2. 求出 $ans = \sum\limits_{i=1} ^ {n} \max \{ t_{i-1}, t_i \}$ 并输出。
显然按照上面模拟是$ O(n^2) $算法。
我们可以这样做,先把$a_i$每个元素记录它的值$val$和下标$i$,排序。
那么求一个前缀$ maxpos=max{a[i].id , maxpos }$,显然遍历到i位置的时候,前面都是比$ a[i] $ 的值,然后前面最大的$ id $号码就是$ maxpos $。
那么时间复杂度就降到$ O(nlog_2n) $
# include <bits/stdc++.h>
# define int long long
using namespace std;
const int N=1e5+;
struct rec{ int val,id; }a[N];
int n,t[N];
bool cmp(rec a,rec b)
{
if (a.val!=b.val) return a.val<b.val;
else return a.id<b.id;
}
signed main()
{
scanf("%lld",&n);
for (int i=;i<=n;i++)
scanf("%lld",&a[i].val),a[i].id=i;
sort(a+,a++n,cmp);
int maxpos=;
for (int i=;i<=n;i++) {
maxpos=max(maxpos,a[i].id);
t[i]=max(1ll,maxpos-i);
}
int ans=;
for (int i=;i<=n;i++)
ans+=max(t[i],t[i-]);
cout<<ans;
return ;
}
问题G: 3900: Out of Sorts
这个题目非常有价值,我想专门开一个blog讲一讲这个题。
https://www.cnblogs.com/ljc20020730/p/10467324.html
欢迎支持!!!
【杂题1】USACO 2018 Open Contest-练习的更多相关文章
- [USACO 2018 December Contest]作业总结
t1 Convention 题目大意 每一头牛都有一个来的时间,一共有\(n\)辆车,求出等待时间最长的那头牛等待的最小时间. 解法 第一眼看到这道题还以为是\(2018noip\)普及组的t3魔鬼题 ...
- [USACO 2018 Open Contest]作业总结
t1-Out of Sorts 题目大意 将最大的数冒泡排序到最后需要多少次操作. 分析 排序后判断距离. ac代码 #include<bits/stdc++.h> #define N 1 ...
- 【二分+拓扑排序】Milking Order @USACO 2018 US Open Contest, Gold/upc_exam_6348
目录 Milking Order @USACO 2018 US Open Contest, Gold/upc_exam_6348 PROBLEM 题目描述 输入 输出 样例输入 样例输出 提示 MEA ...
- 【USACO 2019 Feburary Contest】Gold
模拟二月金组,三个半小时AK. USACO 2019 Feburary Contest, Gold T1 题意:给定一棵树,每个点有点权,每次可以进行以下操作之一: 更改一个点的点权 求某条路径上的点 ...
- [USACO 2018 Feb Gold] Tutorial
Link: USACO 2018 Feb Gold 传送门 A: $dp[i][j][k]$表示前$i$个中有$j$个0且末位为$k$的最优解 状态数$O(n^3)$ #include <bit ...
- 贪心/构造/DP 杂题选做Ⅲ
颓!颓!颓!(bushi 前传: 贪心/构造/DP 杂题选做 贪心/构造/DP 杂题选做Ⅱ 51. CF758E Broken Tree 讲个笑话,这道题是 11.3 模拟赛的 T2,模拟赛里那道题的 ...
- COCI 2018/2019 CONTEST #2 T4 Maja T5Sunčanje Solution
COCI 2018/2019 CONTEST #2 T4 T5 Solution abstract 花式暴力 #2 T5 Sunčanje 题意 按顺序给你1e5个长方形(左下角坐标&& ...
- [USACO 2018 Jan Gold] Tutorial
Link: USACO 2018 Jan Gold 传送门 A: 对于不同的$k$,发现限制就是小于$k$的边不能走 那么此时的答案就是由大于等于$k$的边形成的图中$v$所在的连通块除去$v$的大小 ...
- 正睿OI DAY3 杂题选讲
正睿OI DAY3 杂题选讲 CodeChef MSTONES n个点,可以构造7条直线使得每个点都在直线上,找到一条直线使得上面的点最多 随机化算法,check到答案的概率为\(1/49\) \(n ...
- dp杂题(根据个人进度选更)
----19.7.30 今天又开了一个新专题,dp杂题,我依旧按照之前一样,这一个专题更在一起,根据个人进度选更题目; dp就是动态规划,本人认为,动态规划的核心就是dp状态的设立以及dp转移方程的推 ...
随机推荐
- b/s程序真的很方便部署吗
公共应用当然是web系统,这个不说,我说的是企业应用. 最近一些年在企业开发中都提倡web应用,仿佛winform可以结束了,但真的这样吗?最近几天的真实经历如下: 我们部门新开发了一套系统要上线,由 ...
- Codeforces 987E Petr and Permutations(数组的置换与复原 、结论)
题目连接: Petr and Permutations 题意:给出一个1到n的序列,Petr打乱了3n次,Um_nik打乱了7n+1次,现在给出被打乱后的序列,求是谁打乱的. 题解:因为给出了一个3* ...
- .NET持续集成与自动化部署之路第一篇——半天搭建你的Jenkins持续集成与自动化部署系统
.NET持续集成与自动化部署之路第一篇(半天搭建你的Jenkins持续集成与自动化部署系统) 前言 相信每一位程序员都经历过深夜加班上线的痛苦!而作为一个加班上线如家常便饭的码农,更是深感其痛 ...
- JAVA消息确认机制之ACK模式
JMS API中约定了Client端可以使用四种ACK模式,在javax.jms.Session接口中: AUTO_ACKNOWLEDGE = 1 自动确认 CLIENT_ACKNOWLEDGE ...
- RDMA技术解析
文章出处:https://mp.weixin.qq.com/s/pW-tQR4AYr1Gtd4dpHVW7w 摘要:远程直接内存访问(即Remote Direct Memory Access)是一种直 ...
- GlusterFS分布式存储集群部署记录-相关补充
接着上一篇Centos7下GlusterFS分布式存储集群环境部署记录文档,继续做一些补充记录,希望能加深对GlusterFS存储操作的理解和熟悉度. ======================== ...
- v-for v-if || v-else
<el-col> <div v-for="item in resultDetail" class="physical-content" v-i ...
- C. Maximum Subrectangle
链接 [http://codeforces.com/contest/1060/problem/C] 题意 给你两个数列,可以构成一个矩阵C,ci,j=ai⋅bj 1≤x1≤x2≤n , 1≤y1≤y2 ...
- 无限级结构SQL查询所有的下级和所有的下级
Id,PId无限级结构,查询某个Id的所有下级或所有上级,使用WITH AS查询 查找Id为1所有的下级 /*查找Id为1所有的下级*/ WITH T AS( SELECT Id,PId,Name,0 ...
- 如何使squild服务只能使用自定义的端口号
编辑配置文件: vim /etc/squid/squid.conf http_port 10000 使用 setsebool 命令来限制 squild 服务只能使用自定义的端口: setsebool ...