NOIP2013 提高组 Day1
https://www.luogu.org/problem/lists?name=&orderitem=pid&tag=83%7C30
期望得分:100+100+100=300
实际得分:100+10+0=110
T2 思路有漏洞
T3 求到lca的什么什么值,指跳了一个点,没管另一个,丢100
T1 转圈游戏
题目描述
n 个小伙伴(编号从 0 到 n-1)围坐一圈玩游戏。按照顺时针方向给 n 个位置编号,从0 到 n-1。最初,第 0 号小伙伴在第 0 号位置,第 1 号小伙伴在第 1 号位置,……,依此类推。游戏规则如下:每一轮第 0 号位置上的小伙伴顺时针走到第 m 号位置,第 1 号位置小伙伴走到第 m+1 号位置,……,依此类推,第n − m号位置上的小伙伴走到第 0 号位置,第n-m+1 号位置上的小伙伴走到第 1 号位置,……,第 n-1 号位置上的小伙伴顺时针走到第m-1 号位置。
现在,一共进行了 10^k轮,请问 x 号小伙伴最后走到了第几号位置。
输入输出格式
输入格式:
输入文件名为 circle.in。
输入共 1 行,包含 4 个整数 n、m、k、x,每两个整数之间用一个空格隔开。
输出格式:
输出文件名为 circle.out。
输出共 1 行,包含 1 个整数,表示 10
k 轮后 x 号小伙伴所在的位置编号。
输入输出样例
10 3 4 5
5
说明
对于 30%的数据,0 < k < 7;
对于 80%的数据,0 < k < 10^7;
对于 100%的数据,1 <n < 1,000,000,0 < m < n,1 ≤ x ≤ n,0 < k < 10^9
每次移动m个位置,共移动10^k次,
用快速幂算出移动的总步数,加上x再%n
#include<cstdio>
#include<cmath>
using namespace std;
int n,m,k,x;
long long tmp=;
void mul(long long a,long long b)
{
for(;b;b>>=,a=a*a%n)
if(b&) tmp=tmp*a%n;
tmp=m*tmp%n;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&k,&x);
mul(,k);
printf("%d",(x+tmp)%n);
}
T2 火柴排队
题目描述
涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ∑(ai-bi)^2
其中 ai 表示第一列火柴中第 i 个火柴的高度,bi 表示第二列火柴中第 i 个火柴的高度。
每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 99,999,997 取模的结果。
输入输出格式
输入格式:
输入文件为 match.in。
共三行,第一行包含一个整数 n,表示每盒中火柴的数目。
第二行有 n 个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。
第三行有 n 个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。
输出格式:
输出文件为 match.out。
输出共一行,包含一个整数,表示最少交换次数对 99,999,997 取模的结果。
输入输出样例
【输入输出样例 1】
4
2 3 1 4
3 2 1 4
【输入输出样例 2】
4
1 3 4 2
1 7 2 4
【输入输出样例 1】
1
【输入输出样例 2】
2
说明
【输入输出样例说明1】
最小距离是 0,最少需要交换 1 次,比如:交换第 1 列的前 2 根火柴或者交换第 2 列的前 2 根火柴。
【输入输出样例说明2】
最小距离是 10,最少需要交换 2 次,比如:交换第 1 列的中间 2 根火柴的位置,再交换第 2 列中后 2 根火柴的位置。
【数据范围】
对于 10%的数据, 1 ≤ n ≤ 10;
对于 30%的数据,1 ≤ n ≤ 100;
对于 60%的数据,1 ≤ n ≤ 1,000;
对于 100%的数据,1 ≤ n ≤ 100,000,0 ≤火柴高度≤ maxlongint
∑(ai-bi)^2=Σ ai² + Σ bi² - 2 Σ ai * bi
ai² ,b²是固定的
所以要最大化 ai * bi
下意识觉得 将a、b排序后对应顺序相乘的结果最大,正确
证明如下:
由排序不等式:
设有两组数 a1 , a2 ,…… an; b1 , b2 ,…… bn 满足 a1 ≤ a2 ≤……≤ an, b1 ≤ b2 ≤……≤ bn ,
其中c1,c2,……,cn是b1,b2,……,bn的任一排列,则有
a1* bn + a2 *b{n-1}+ ... + an *b1
≤ a1 *c1 + a2* c2 +……+ an *cn
≤ a1 *b1 + a2 *b2 + ……+an* bn.
即 逆序和<=乱序和<=顺序和
所以最大化ai * bi,就要顺序相乘
所以问题就转化为
在b数组中,交换最少的次数,
使得 若a[i]在a数组中排名为j,b[i]也在b数组中排名为j
设一个数组s,s[i]=j表示 b原序列中第i个元素,应该在位置j
然后问题转化为了求s[]的逆序对个数
AC代码:
#include<cstdio>
#include<algorithm>
#define N 100001
#define mod 99999997
using namespace std;
int n,ans,tmp[N],s[N];
struct node
{
int w,id;
}a[N],b[N];
bool cmp(node p,node q)
{
return p.w<q.w;
}
void solve(int l,int r)
{
if(l==r) return;
int mid=l+r>>;
solve(l,mid);
solve(mid+,r);
int i=l,j=mid+,k=l;
while(i<=mid&&j<=r)
{
if(s[i]<=s[j]) tmp[k++]=s[i++];
else
{
ans=(ans+mid-i+)%mod;
tmp[k++]=s[j++];
}
}
while(i<=mid) tmp[k++]=s[i++];
while(j<=r) tmp[k++]=s[j++];
for(int i=l;i<=r;i++) s[i]=tmp[i];
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++) scanf("%d",&a[i].w),a[i].id=i;
for(int i=;i<=n;i++) scanf("%d",&b[i].w),b[i].id=i;
sort(a+,a+n+,cmp);
sort(b+,b+n+,cmp);
for(int i=;i<=n;i++) s[b[i].id]=a[i].id;
solve(,n);
printf("%d",ans);
}
自己做的错误思路:
将a数组从大到小排序,对应的b随之排序,求b中 i>j,b[i]<b[j]的个数
错误1:
逆序对定义:i<j,a[i]>a[j],归并排序求逆序对模版是按i<j来的
错误2:
重排a数组,b数组随之排,这样归并排序完后得到b的循序序列
但改变了a数组,即改变了原序列
WA 10分代码:
#include<cstdio>
#include<algorithm>
#define N 100001
#define mod 99999997
using namespace std;
int n,ans,tmp[N],s[N];
struct node
{
int a,b;
}e[N];
bool cmp(node p,node q)
{
return p.a<q.a;
}
void solve(int l,int r)
{
if(l==r) return;
int mid=l+r>>;
solve(l,mid);
solve(mid+,r);
int i=l,j=mid+,k=l;
while(i<=mid&&j<=r)
{
if(s[i]<=s[j]) tmp[k++]=s[i++];
else
{
ans=(ans+mid-i+)%mod;
tmp[k++]=s[j++];
}
}
while(i<=mid) tmp[k++]=s[i++];
while(j<=r) tmp[k++]=s[j++];
for(int i=l;i<=r;i++) s[i]=tmp[i];
}
int main()
{
/*freopen("data","r",stdin);
freopen("my.out","w",stdout);*/
scanf("%d",&n);
for(int i=;i<=n;i++) scanf("%d",&e[i].a);
for(int i=;i<=n;i++) scanf("%d",&e[i].b);
sort(e+,e+n+,cmp);
for(int i=;i<=n;i++) s[i]=e[i].b;
solve(,n);
printf("%d",ans);
}
T3 货车运输
题目描述
A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
输入输出格式
输入格式:
输入文件名为 truck.in。
输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道
路。 接下来 m 行每行 3 个整数 x、 y、 z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意: x 不等于 y,两座城市之间可能有多条道路 。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意: x 不等于 y 。
输出格式:
输出文件名为 truck.out。
输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货
车不能到达目的地,输出-1。
输入输出样例
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
3
-1
3
说明
对于 30%的数据,0 < n < 1,000,0 < m < 10,000,0 < q< 1,000;
对于 60%的数据,0 < n < 1,000,0 < m < 50,000,0 < q< 1,000;
对于 100%的数据,0 < n < 10,000,0 < m < 50,000,0 < q< 30,000,0 ≤ z ≤ 100,000。
题意:若点x、y连通,求x、y路径上限重的最小值;若不连通,输出-1
注:数据有重边、有环
重边肯定保留限重最大的那一条,所选的道路限重越大越好
所以 是最大生成树
在最大生成树上倍增,同时维护倍增区域的最小值
答案就是两点到其lca路径上,所有倍增区域的最小值
#include<map>
#include<cmath>
#include<cstdio>
#include<algorithm>
#define N 10001
using namespace std;
int timee,n,m,p,ances[N][],id[N],minn[N][],tot,q;
int front[N],nextt[N*],to[N*],w[N*];
int bl[N],k,fa[N],cnt;
struct node
{
int u,v,c;
}e[N*];
void dfs(int x)
{
id[x]=++cnt;
bl[x]=timee;
for(int i=front[x];i;i=nextt[i])
{
if(to[i]==ances[x][]) continue;
ances[to[i]][]=x;
minn[to[i]][]=w[i];
dfs(to[i]);
}
}
void add(int u,int v,int val)
{
to[++tot]=v; nextt[tot]=front[u]; front[u]=tot; w[tot]=val;
}
void pre()
{
for(int i=;i<=n;i++)
if(!id[i])
{
timee++;
dfs(i);
}
int tmp;
q=int(log(n)/log()+);
for(int i=;i<=q;i++)
for(int j=;j<=n;j++)
{
ances[j][i]=ances[ances[j][i-]][i-];
if(!ances[j][i]) continue;
tmp=min(minn[j][i-],minn[ances[j][i-]][i-]);
minn[j][i]=tmp;
}
}
int find(int i) {return fa[i]==i ? fa[i] : fa[i]=find(fa[i]);}
void solve(int x,int y)
{
if(bl[x]!=bl[y])
{
printf("-1\n");
return;
}
int ans=;
if(id[x]<id[y]) swap(x,y);
for(int i=q;i>=;i--)
if(id[ances[x][i]]>id[y])
{
ans=min(ans,minn[x][i]);
x=ances[x][i];
}
ans=min(ans,minn[x][]);
x=ances[x][];
if(x!=y)
{
for(int i=q;i>=;i--)
if(id[ances[y][i]]>id[x])
{
ans=min(ans,minn[y][i]);
y=ances[y][i];
}
ans=min(ans,minn[y][]);
}
printf("%d\n",ans);
}
bool cmp(node a,node b)
{
return a.c>b.c;
}
void make_tree()
{
int a,b,j=,r1,r2;
int h=;
while(h<n-&&j<=m)
{
a=e[j].u;b=e[j].v;
r1=find(a);r2=find(b);
if(r1!=r2)
{
h++;
fa[r1]=r2;
add(a,b,e[j].c);add(b,a,e[j].c);
}
j++;
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) fa[i]=i;
int u,v,a;
for(int i=;i<=m;i++)
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].c);
sort(e+,e+m+,cmp);
make_tree();
pre();
scanf("%d",&p);
while(p--)
{
scanf("%d%d",&u,&v);
solve(u,v);
}
}
考试时的错误:
1、跳了x没跳y
2、跳y之前没有判断y是否就是lca
NOIP2013 提高组 Day1的更多相关文章
- noip2013提高组day1第一题-转圈游戏——快速幂典型应用
所谓的快速幂: // 计算 m^n % k 的快速幂算法 int quickpow(int m,int n,int k) { ; ) { ) b = (b*m)%k; n = n >> ; ...
- JZOJ 3534. 【NOIP2013提高组day1】货车运输
Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的 ...
- luogu1003铺地毯[noip2011 提高组 Day1 T1]
题目描述 为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有 n 张地毯,编号从 1 到n .现在将这些地毯按照编号从小到大的顺序平行于 ...
- [NOIp2013提高组]积木大赛/[NOIp2018提高组]铺设道路
[NOIp2013提高组]积木大赛/[NOIp2018提高组]铺设道路 题目大意: 对于长度为\(n(n\le10^5)\)的非负数列\(A\),每次可以选取一个区间\(-1\).问将数列清零至少需要 ...
- 18/9/9牛客网提高组Day1
牛客网提高组Day1 T1 中位数 这好像是主席树??听说过,不会啊... 最后只打了个暴力,可能是n2logn? 只过了前30% qwq #include<algorithm> #in ...
- Noip2011 提高组 Day1 T1 铺地毯 + Day2 T1 计算系数
Day1 T1 题目描述 为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有 n 张地毯,编号从 1 到n .现在将这些地毯按照编号从小 ...
- Noip2011 提高组 Day1 T3 Mayan游戏
题目描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个 7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.游戏通关是指在规定 ...
- GZOJ 1361. 国王游戏【NOIP2012提高组DAY1】
国王游戏[NOIP2012提高组DAY1] Time Limit:1000MS Memory Limit:128000K Description 国王游戏(game.cpp/c/pas) [问题描述] ...
- [NOIP2013 提高组] 华容道 P1979 洛谷
[NOIP2013 提高组] 华容道 P1979 洛谷 强烈推荐,更好的阅读体验 经典题目:spfa+bfs+转化 题目大意: 给出一个01网格图,和点坐标x,y空格坐标a,b,目标位置tx,ty要求 ...
随机推荐
- Hadoop环境搭建01
根据马士兵老师的Hadoop进行的配置 1.首先列下来需要用到的软件 VirtulBox虚拟机.Centos7系统镜像.xshell.xftp.jdk安装包.hadoop-2.7.0安装包 2.在Vi ...
- 第一次c++团队合作项目第三篇随笔
这次终于想出来了上次问题的解决方法,就是用多态的方法,让小兵,建筑和英雄继承于Object类,通过指针能实现信息的传递. 同时我也完善了地图中每个Pane类的信息,包括每个格子的位置信息,state( ...
- <浪潮之巅>读书笔记
<浪潮之巅>这本书通过介绍AT&T.IBM.微软.苹果.google等IT公司的发展历史,揭示科技工业的胜败规律,说明这些公司是如何在每一次科技革命浪潮到来时站在浪尖,实现跨越式发 ...
- 【final】140字互评②
按照产品发布顺序 nice!----约吧 我们的团队展示相对于上次的手足无措,有了一定进步.但是整体还是不那么流畅总结起来的缺点是: 1.发布时,摄像头不清晰 且抖动 我们没有把摄像头固定,并且为了让 ...
- gulp 定义依赖关系
var gulp = require('gulp'); // 返回一个 callback,因此系统可以知道它什么时候完成 gulp.task('one', function(cb) { // 做一些事 ...
- Java ISO 8601时间格式转换
common-lang包: String pattern = "YYYY-MM-dd'T'HH:mm:ssZZ"; System.out.println(DateFormatUti ...
- jmeter同步定时器
同步定时器是jmeter中一个比较重要的定时器,同步定时器,相当于一个储蓄池,累积一定的请求,当在规定的时间内达到一定的线程数量,这些线程会在同一个时间点一起并发,可以用来做大数据量的并发请求. 验证 ...
- BZOJ3875 AHOI2014/JSOI2014骑士游戏(动态规划)
容易想到设f[i]为杀死i号怪物所消耗的最小体力值,由后继节点更新.然而这显然是有后效性的,正常的dp没法做. 虽然spfa已经死了,但确实还是挺有意思的.只需要用spfa来更新dp值就可以了.dij ...
- 【bzoj1878】[SDOI2009]HH的项链
考虑非莫队的离线算法.. 若[l,r]中有重复数值很麻烦,考虑取一个数为代表(最左或最右) 1.最左:用BIT,先把所有第一个出现的数扔进去,将询问左端点升序,每次都可能产生历史的无用点,并出现新的“ ...
- C++11新利器
C++11常用特性的使用经验总结 unordered_map可能用的会比较多 省的写哈希表了. 但是浪费空间