唉……第二天依然被虐……但是比第一天好一点……我必须负责任的指出:志灿大神出的题比柯黑的不知道靠谱到哪里去了……柯黑出的简直不可做

但是被虐的命运是无法改变的……求各位神犇别D我

黄巨大真是强啊,不愧是福建省现役最强!连A两题之后第三题写了个暴力随机点+最小生成树的多跑了几次竟然各种乱A……还把std给hack了……rank1的巨大神!@陈*瑶

【题目描述】

二维平面上有n个点(xi, yi),现在这些点中取若干点构成一个集合S,对它们按照x坐标排序,顺次连接,将会构成一些连续上升、下降的折线,设其数量为f(S)。如下图中,1->2,2->3,3->5,5->6(数字为下图中从左到右的点编号),将折线分为了4部分,每部分连续上升、下降。

现给定k,求满足f(S) = k的S集合个数。

【输入格式】

第一行两个整数n和k,以下n行每行两个数(xi, yi)表示第i个点的坐标。所有点的坐标值都在[1, 100000]内,且不存在两个点,x坐标值相等或y坐标值相等。

【输出格式】

输出满足要求的方案总数 mod100007的结果。

【样例输入】

5 1

5 5

3 2

4 4

2 3

1 1

【样例输出】

19

【数据范围】

对于10%的数据,n <= 10, k = 1

对于30%的数据,n <= 1000, k = 1

对于50%的数据,n <= 1000, k <= 10

对于100%的数据,n <= 50000,0 < k <= 10

第一题可做……就是带优化的dp。但是我逗比了……考场上没想出方程……幸好我及时orz了hzwer巨大神

n^2*m暴力还是可写的

首先按x坐标sort一下,把y坐标提出来。这基本上没问题

用f[i][j][0/1]表示选了第i个点、一共有j段折线、最后一段是上升(1)或者下降(0)的方案数

这里不能选前i个点,因为这样不能知道第i个点是选了还是没选。

所以f[i][j][1]=Σf[k][j][1]+f[k][j-1][0],其中y[k]>y[i]

f[i][j][0]=Σf[k][j][0]+f[k][j-1][1],其中y[k]<y[i];

具体实现什么的看代码吧

#include<cstdio>
#include<iostream>
#include<algorithm>
#define mod 100007
using namespace std;
struct point{
int x,y;
}p[100001];
inline bool cmp(const point &a,const point &b)
{
return a.x<b.x;
}
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,sum;
int a[100001];
int f[1001][1001][2];
int main()
{
freopen("line.in","r",stdin);
freopen("line.out","w",stdout);
n=read();m=read();
for (int i=1;i<=n;i++)p[i].x=read(),p[i].y=read();
sort(p+1,p+n+1,cmp);
for (int i=1;i<=n;i++)a[i]=p[i].y;
for (int i=1;i<=n;i++)
{
f[i][0][0]=f[i][0][1]=1;
for (int j=1;j<=m;j++)
{ for (int k=1;k<i;k++)
if (a[k]<a[i])
{
f[i][j][1]+=f[k][j][1];
if (j)f[i][j][1]+=f[k][j-1][0];
while(f[i][j][1]>mod) f[i][j][1]-=mod;
}
else
{
f[i][j][0]+=f[k][j][0];
if (j)f[i][j][0]+=f[k][j-1][1];
while(f[i][j][0]>mod) f[i][j][0]-=mod;
}
}
}
for (int i=1;i<=n;i++)
sum=(sum+f[i][m][0]+f[i][m][1])%mod;
printf("%d",sum);
}

那么这样dp时间效率是n^2*m的,肯定要T

所以可以考虑维护一个树状数组、以y为关键字,这样可以优化到n*logn*m

刚考完cf又掉rating 没心情再写了。直接上黄巨大代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define ll long long
#define inf 100000000
#define mod 100007
using namespace std;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,ans;
int t[15][2][100005];
int f[100005][15][2];//0ΪÉÏÉý1ΪϽµ
struct data{int x,y;}p[100005];
inline bool operator<(data a,data b)
{return a.x<b.x;}
inline int lowbit(int x)
{return x&(-x);}
inline void add(int x,int v,int j,int k)
{
for(int i=x;i<=100000;i+=lowbit(i))
t[j][k][i]=(t[j][k][i]+v)%mod;
}
inline int que(int x,int j,int k)
{
int sum=0;
for(int i=x;i;i-=lowbit(i))
sum=(sum+t[j][k][i])%mod;
return sum;
}
void solve1()
{
for(int i=1;i<=n;i++)
{
f[i][0][0]=f[i][0][1]=1;
for(int j=1;j<i;j++)
for(int k=1;k<=m;k++)
{
if(p[j].y<p[i].y)f[i][k][0]+=f[j][k][0]+f[j][k-1][1];
else f[i][k][1]+=f[j][k][1]+f[j][k-1][0];
f[i][k][0]%=mod;f[i][k][1]%=mod;
}
}
for(int i=1;i<=n;i++)
{
ans=(ans+f[i][m][0])%mod;
ans=(ans+f[i][m][1])%mod;
}
printf("%d\n",ans);
}
void solve2()
{
for(int i=1;i<=n;i++)
{
f[i][0][0]=f[i][0][1]=1;
add(p[i].y,1,0,0);add(p[i].y,1,0,1);
for(int j=1;j<=m;j++)
{
f[i][j][0]+=que(p[i].y-1,j,0)+que(p[i].y-1,j-1,1);
f[i][j][1]+=que(100000,j,1)-que(p[i].y,j,1)+que(100000,j-1,0)-que(p[i].y,j-1,0);
f[i][j][0]%=mod;f[i][j][1]%=mod;
if(f[i][j][1]<0)f[i][j][1]+=mod;
add(p[i].y,f[i][j][0],j,0);add(p[i].y,f[i][j][1],j,1);
}
}
for(int i=1;i<=n;i++)
{
ans=(ans+f[i][m][0])%mod;
ans=(ans+f[i][m][1])%mod;
}
printf("%d\n",ans);
}
int main()
{
freopen("line.in","r",stdin);
freopen("line.out","w",stdout);
n=read();
m=read();
for(int i=1;i<=n;i++)
p[i].x=read(),p[i].y=read();
sort(p+1,p+n+1);
if(n<=1000)solve1();
else solve2();
return 0;
}

你看他写得多好啊

还是我太弱了

【题目描述】

给定n个非负整数A[1], A[2], ……, A[n]。

对于每对(i, j)满足1 <= i < j <= n,得到一个新的数A[i] xor A[j],这样共有n*(n-1)/2个新的数。求这些数(不包含A[i])中前k小的数。

注:xor对应于pascal中的“xor”,C++中的“^”。

【输入格式】

第一行2个正整数 n,k,如题所述。

以下n行,每行一个非负整数表示A[i]。

【输出格式】

共一行k个数,表示前k小的数。

【样例输入】

4 5

1

1

3

4

【样例输出】

0 2 2 5 5

【样例解释】

1 xor 1 = 0 (A[1] xor A[2])

1 xor 3 = 2 (A[1] xor A[3])

1 xor 4 = 5 (A[1] xor A[4])

1 xor 3 = 2 (A[2] xor A[3])

1 xor 4 = 5 (A[2] xor A[4])

3 xor 4 = 7 (A[3] xor A[4])

前5小的数:0 2 2 5 5

【数据范围】

第一个数据点,n <= 1000;

第二个数据点,k = 1;

对于40%的数据,n <= 10000; k <= 10;

对于60%的数据,n <= 20000;

对于100%的数据,2 <= n <= 100000; 1 <= k <= min{250000, n*(n-1)/2};

0 <= A[i] < 231

这题实在是……

首先,n^2暴力是很好搞的。

其次,q=1的情况也是可做的。据鸿巨大说要用trie树搞

最后,来讲一种我在考场上想到的很奇怪的算法(反正能A就是爷)

以样例为例,先把所有数转成2进制:

001

001

011

100

我的做法是首先把第一位是0的和第一位是1的分开,那么就形成了两块。注意到同一块中的数相互异或肯定第一位是0(因为第一位相同),而在第一块中取一个再从第二块中取一个作异或,肯定第一位是1。这样我们证明了从同一块中挑选一定是优于跨越这一块从另外一块选一个拿去异或。比如说,001、001、011被划分成一块,100被划分成另一块。那么显然在同块中的异或结果更优。比如001^001=0,001^011=2,都优于100^001=5,100^011=7。那分成2块以后还能不能再这样分成4块呢?答案是肯定的。

那么推广一下:把数据快排,暴力根据前几位的状态建一棵树,根节点是所有数,左节点是开头是‘0’的数的区间(快排后这些数肯定在一个区间内而不是被离散),右节点是开头是‘1’的数的区间。树的第三层分别是开头是‘00’‘01’‘10’‘11’的数的区间……这样树就建完了。它是长这样的:(画的丑勿喷)

那么显然这棵树最坏情况下有31层即log(maxlongint),对于每一层我们都可以用n^2暴力枚举树节点上的答案,然后sort。这样画的层数越多,n^2的平摊效果越好。然而我们要保证解数>=k,所以要一层上面Σ(len[i]*len[i-1]/2)>=k。显然我们可以保存每一层产生的数字对数,从上往下找到第一个小于k的,我们就直接暴力枚举ans。

比如第一层根节点最多产生4*3/2=6个,超过5

第二层最多产生3*2/2=3个,不到5

所以我们只好从根节点枚举,这样效率n^2了

不过数据完全随机且比较大,应该不会出现恶意去卡的情况。要不然对于极限数据比如任何a[i]都=1的直接特判一下。

ps:我和黄巨大交流的时候我跟他讲了一下,然后他写了一个暴力A了,我还要做死地把建树的for改成二分,结果又wa又t一时爽……我还是太弱了

对于极限数据比如任何a[i]都=1的直接特判一下。

就不贴我写的丑丑的代码了,贴黄巨大的
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define ll long long
#define inf 100000000
using namespace std;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,num;
int a[100005],b[1000005];
int bin[35],tmp[35][100005];
ll cnt[35];
void solve1()
{
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
b[++num]=(a[i]^a[j]);
sort(b+1,b+num+1);
for(int i=1;i<=m;i++)
printf("%d ",b[i]);
}
void cal(int l,int r,int k)
{
if(l>=r)return;
int tot=0;
for(int i=l;i<=r;i++)
if(tmp[k+1][i]&bin[k])tot++;
int L=l-1,R=l+tot-1;
for(int i=l;i<=r;i++)
if(tmp[k+1][i]&bin[k])tmp[k][++L]=tmp[k+1][i];
else tmp[k][++R]=tmp[k+1][i];
if(k!=0){cal(l,l+tot-1,k-1);cal(l+tot,r,k-1);}
cnt[k]+=(ll)(r-l+1)*(r-l)/2;
}
void print(int l,int r,int k,int x)
{
if(l>=r)return;
if(k==x)
{
for(int i=l;i<=r;i++)
for(int j=i+1;j<=r;j++)
b[++num]=tmp[x+1][i]^tmp[x+1][j];
return;
}
int tot=0;
for(int i=l;i<=r;i++)
if(tmp[k+1][i]&bin[k])tot++;
if(k!=0){print(l,l+tot-1,k-1,x);print(l+tot,r,k-1,x);}
}
void solve2()
{
for(int i=1;i<=n;i++)tmp[31][i]=a[i];
cal(1,n,30);
bool flag=0;
for(int i=30;i>=0;i--)
if(cnt[i]<m){print(1,n,30,i+1);flag=1;break;}
if(!flag)print(1,n,30,0);
sort(b+1,b+num+1);
for(int i=1;i<=m;i++)
printf("%d ",b[i]);
}
int main()
{
freopen("xorit.in","r",stdin);
freopen("xorit.out","w",stdout);
bin[0]=1;for(int i=1;i<=31;i++)bin[i]=bin[i-1]*2;
n=read(),m=read();
for(int i=1;i<=n;i++)
a[i]=read();
if(n<=1000)solve1();
else solve2();
return 0;
}

除此之外,各位大神们还想出了很多其他做法,我承认自己yy根本做不到。

鸿巨大指出:哎这不是“超级钢琴”原题吗?看我写堆+可持久trieA掉它……结果T了三个点。最后鸿巨大还是自豪的说,我的算法是稳定的……只是T了而已……
翁家弈的做法是在正常的两个for里加上剪枝,就是abs(a-b)<=a^b<=abs(a+b)还是什么的忘记了,但是这样可以卡时限A掉。这样应该也算随机化算法。
总之,大神的世界我们怎么会懂……

【题目描述】

给定二维平面上n个整点,求该图的一个直线斯坦纳树,使得树的边长度总和尽量小。

直线斯坦纳树:使所有给定的点连通的树,所有边必须平行于坐标轴,允许在给定点外增加额外的中间节点。

【输入格式】

第一行一个整数n,表示点数。

以下n行,每行两个整数表示点的x,y坐标。

【输出格式】

第一行一个整数m,表示中间节点的个数。

必须满足m <= 10 * n

以下m行,每行2个整数表示中间节点的坐标。

以下n+m-1行,每行2个整数u,v表示编号为u和v的两个节点之间有边直接相连,边的权值为两点的曼哈顿距离,即|x[u] – x[v]|+ |y[u] – y[v]|

输入数据给定的点的编号为1..n,选手输出的中间节点的编号为n+1..n+m

【样例输入】

4

-1 0

0 -1

1 0

0 1

【样例输出】

1

0 0

1 5

2 5

3 5

4 5

【格式说明】

选手可使用test.exe对数据进行测试

在命令行下使用“test x”即可测试rsmtx.in和rsmtx.out

(注:x必须是一个字符,即“test 1234”等价于“test 1”)

【题目描述】

给定二维平面上n个整点,求该图的一个直线斯坦纳树,使得树的边长度总和尽量小。

直线斯坦纳树:使所有给定的点连通的树,所有边必须平行于坐标轴,允许在给定点外增加额外的中间节点。

【输入格式】

第一行一个整数n,表示点数。

以下n行,每行两个整数表示点的x,y坐标。

【输出格式】

第一行一个整数m,表示中间节点的个数。

必须满足m <= 10 * n

以下m行,每行2个整数表示中间节点的坐标。

以下n+m-1行,每行2个整数u,v表示编号为u和v的两个节点之间有边直接相连,边的权值为两点的曼哈顿距离,即|x[u] – x[v]|+ |y[u] – y[v]|

输入数据给定的点的编号为1..n,选手输出的中间节点的编号为n+1..n+m

【样例输入】

4

-1 0

0 -1

1 0

0 1

【样例输出】

1

0 0

1 5

2 5

3 5

4 5

【格式说明】

选手可使用test.exe对数据进行测试

在命令行下使用“test x”即可测试rsmtx.in和rsmtx.out

(注:x必须是一个字符,即“test 1234”等价于“test 1”)

这题前4个点n=8,是状压dp:f[x][y][s]表示当前过点(x,y),点之间的联通性是s的最小边数,然后乱搞

5到8个点是插头dp……根本不会

最后两个点暴搜吧

结果黄巨大写的神rand居然拿下70分,而且最后两个点还把志灿hack了……真不知是该膜拜呢还是膜拜呢还是膜拜

福建省队集训被虐记——DAY2的更多相关文章

  1. 福建省队集训被虐记——DAY4

    啊啊啊啊啊啊第四天考的是我最不擅长的图论--整个人都斯巴达了 //另外不得不吐槽下午的上课讲的都是网络流--难道是出题人觉得图论里除了网络流以外的其他算法都没有人权图样图森破? 愚蠢的算法(clums ...

  2. 福建省队集训被虐记——DAY3

    昨天没写--今天补上吧 一如既往的跪了 棋盘 [问题描述] 给出一个N*M的方格棋盘,每个格子里有一盏灯和一个开关,开始的时候,所有的灯都是关着的.用(x, y)表示第x行,y列的格子.(x, y)的 ...

  3. 福建省队集训被虐记——DAY1

    今天算是省冬的第一天--早上柯黑出题,说是"信心欢乐赛",其实是"使你失去信心.不再欢乐的比赛" 顺便orz一下来看这篇文章的各路神犇--求轻虐 水题 (py. ...

  4. zju 校队选拔 被虐记

    选拔已经开始了三天才想起来写游记 QAQ.. 7.12 弱弱的Sky_miner来到了ZJU,过程中被热成狗... 然后见到了无数大二大三的大佬们,过程中被热成狗... 后来听靖哥哥说集训的注意事项, ...

  5. JS省队集训记

    不知不觉省队集训已经结束,离noi也越来越近了呢 论考前实战训练的重要性,让我随便总结一下这几天的考试 Day 1 T1 唉,感觉跟xj测试很像啊?meet in middle,不过这种题不多测是什么 ...

  6. HN2018省队集训

    HN2018省队集训 Day1 今天的题目来自于雅礼的高二学长\(dy0607\). 压缩包下载 密码: 27n7 流水账 震惊!穿着该校校服竟然在四大名校畅通无阻?霸主地位已定? \(7:10\)从 ...

  7. 2018HN省队集训

    HNOI2018省队集训 Day 1 流水账 T1 tree 换根+求\(lca\)+求子树和,一脸bzoj3083遥远的国度的既视感.子树和讨论一下就好了,\(lca\)?也是大力讨论一波. 先写了 ...

  8. 2017FJ省队集训 游记

    2017FJ省队集训 游记 又是一篇流水账 Day 1 今天是省队集训的第一天.早上骑车去八中,到的时候汗流太多浑身湿透被杨哥哥和runzhe2000 d了,一个说我去游泳了一个说我打球了...流完汗 ...

  9. [2018HN省队集训D9T1] circle

    [2018HN省队集训D9T1] circle 题意 给定一个 \(n\) 个点的竞赛图并在其中钦定了 \(k\) 个点, 数据保证删去钦定的 \(k\) 个点后这个图没有环. 问在不删去钦定的这 \ ...

随机推荐

  1. Jquery使用tbody编辑功能实现table输入计算功能

    实例:编写一个输入计算(被减数-减数=差). HTML: <body> <table> <thead> <tr> <td >被减数</ ...

  2. Windows系统基本概念

    windows API:被文档化的可以调用的子例程,如CreateProcess 原生的系统服务(执行体系统服务):未被文档化的.可以再用户模式下调用的底层服务,如NtCreateProcess 内核 ...

  3. lucene3.6.0 经典案例 入门教程

    第一步:下载并导入lucene的核心包(注意版本问题):  例如Lucene3.6版本:将lucene-core-3.6.0.jar拷贝到项目的libs 文件夹里.  例如Lucene4.6版本:将l ...

  4. JAVA并发实现三(线程的挂起和恢复)

    package com.subject01; /** * 通过标识位,实现线程的挂起和回复 * com.subject01.AlternateSuspendResume.java * @author ...

  5. C/C++经典面试题目

    1.关于动态申请内存 答:内存分配方式三种: (1)从静态存储区域分配:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.全局变量,static变量. (2)在栈上创建:在执行函数 ...

  6. NetAnalyzer笔记 之 六 用C#打造自己的网络连接进程查看器(为进程抓包做准备)

    [创建时间:2016-04-13 22:37:00] NetAnalyzer下载地址 起因 最近因为NetAnalyzer2016的发布,好多人都提出是否可以在NetAnalyzer中加入一个基于进程 ...

  7. Hive MapJoin

    摘要 MapJoin是Hive的一种优化操作,其适用于小表JOIN大表的场景,由于表的JOIN操作是在Map端且在内存进行的,所以其并不需要启动Reduce任务也就不需要经过shuffle阶段,从而能 ...

  8. 万恶DevExpress

    公司需要,开始了DevExpress的学习之旅,说它万恶也只是在不了解它的情况下,熟悉之后能很方便的实现很多想要的功能 这里简单写一下要整理的内容,也就是大纲,以后再慢慢添加 一.控件和组件 date ...

  9. [2011山东省第二届ACM大学生程序设计竞赛]——Identifiers

    Identifiers Time Limit: 1000MS Memory limit: 65536K 题目:http://acm.sdut.edu.cn/sdutoj/problem.php?act ...

  10. .NET基础拾遗(5)反射2

    本篇是学习反射的一个应用小场景而做的学习笔记,主要是一个小的总结,并对各个步骤的记录,以便将来回顾. 一.基础框架-敏捷基础版本 这里假定我们要开发一个记事本,选择Windows Form技术开发,界 ...