福建省队集训被虐记——DAY2
唉……第二天依然被虐……但是比第一天好一点……我必须负责任的指出:志灿大神出的题比柯黑的不知道靠谱到哪里去了……柯黑出的简直不可做
但是被虐的命运是无法改变的……求各位神犇别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一时爽……我还是太弱了
#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根本做不到。
【题目描述】
给定二维平面上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的更多相关文章
- 福建省队集训被虐记——DAY4
啊啊啊啊啊啊第四天考的是我最不擅长的图论--整个人都斯巴达了 //另外不得不吐槽下午的上课讲的都是网络流--难道是出题人觉得图论里除了网络流以外的其他算法都没有人权图样图森破? 愚蠢的算法(clums ...
- 福建省队集训被虐记——DAY3
昨天没写--今天补上吧 一如既往的跪了 棋盘 [问题描述] 给出一个N*M的方格棋盘,每个格子里有一盏灯和一个开关,开始的时候,所有的灯都是关着的.用(x, y)表示第x行,y列的格子.(x, y)的 ...
- 福建省队集训被虐记——DAY1
今天算是省冬的第一天--早上柯黑出题,说是"信心欢乐赛",其实是"使你失去信心.不再欢乐的比赛" 顺便orz一下来看这篇文章的各路神犇--求轻虐 水题 (py. ...
- zju 校队选拔 被虐记
选拔已经开始了三天才想起来写游记 QAQ.. 7.12 弱弱的Sky_miner来到了ZJU,过程中被热成狗... 然后见到了无数大二大三的大佬们,过程中被热成狗... 后来听靖哥哥说集训的注意事项, ...
- JS省队集训记
不知不觉省队集训已经结束,离noi也越来越近了呢 论考前实战训练的重要性,让我随便总结一下这几天的考试 Day 1 T1 唉,感觉跟xj测试很像啊?meet in middle,不过这种题不多测是什么 ...
- HN2018省队集训
HN2018省队集训 Day1 今天的题目来自于雅礼的高二学长\(dy0607\). 压缩包下载 密码: 27n7 流水账 震惊!穿着该校校服竟然在四大名校畅通无阻?霸主地位已定? \(7:10\)从 ...
- 2018HN省队集训
HNOI2018省队集训 Day 1 流水账 T1 tree 换根+求\(lca\)+求子树和,一脸bzoj3083遥远的国度的既视感.子树和讨论一下就好了,\(lca\)?也是大力讨论一波. 先写了 ...
- 2017FJ省队集训 游记
2017FJ省队集训 游记 又是一篇流水账 Day 1 今天是省队集训的第一天.早上骑车去八中,到的时候汗流太多浑身湿透被杨哥哥和runzhe2000 d了,一个说我去游泳了一个说我打球了...流完汗 ...
- [2018HN省队集训D9T1] circle
[2018HN省队集训D9T1] circle 题意 给定一个 \(n\) 个点的竞赛图并在其中钦定了 \(k\) 个点, 数据保证删去钦定的 \(k\) 个点后这个图没有环. 问在不删去钦定的这 \ ...
随机推荐
- Dynamic Binding & Static Binding
Reference: JavaPoint BeginnerBook What is Binding Connecting a method call to the method body is kno ...
- HDU5584 LCM Walk 数论
LCM Walk Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Su ...
- 给那些因为Firebug而舍不得FireFox的朋友
Google Chrome浏览器调试 作为Web开发人员,我为什么喜欢Google Chrome浏览器 [原文地址:http://www.cnblogs.com/QLeelulu/archive/20 ...
- Arcgis for js载入天地图
综述:本节讲述的是用Arcgis for js载入天地图的切片资源. 天地图的切片地图能够通过esri.layers.TiledMapServiceLayer来载入.在此将之进行了一定的封装,例如以下 ...
- Play Framework Web开发教程(33): 结构化页面-组合使用模板
和你编写代码相似,你编写的页面也能够由多个小的片段组合而成,这些小的片段本身也能够由更小的片段构成.这些小片段一般是能够在其他页面反复使用的:有些部分能够用在全部页面,而有些部分是某些页面特定的.本篇 ...
- 破解Veeam过程
1)运行Veeam_Backup_Setup.exe,但是不要继续下一步: 2)进入到%temp%\IXP000.TMP目录,例如windows xp sp3环境默认为C:\Documents and ...
- hdu1015(Safecracker )
Problem Description === Op tech briefing, 2002/11/02 06:42 CST === "The item is locked in a Kle ...
- Unity 对象池的使用
在游戏开发过程中,我们经常会遇到游戏发布后,测试时玩着玩着明显的感觉到有卡顿现象.出现这种现象的有两个原因:一是游戏优化的不够好或者游戏逻辑本身设计的就有问题,二是手机硬件不行.好吧,对于作为程序员的 ...
- NVL函数(NVL,NVL2,NULLIF,COALESCE)
NVL 语法:NVL( expr1, expr2) 功能:如果expr1为NULL,则NVL函数返回expr2的值,否则返回expr1的值,如果两个参数的都为NULL ,则返回NULL. 注意事项:e ...
- 安装VMware Sphere ESXi 5.5
安装VMware Sphere ESXi 5.5 1.准备 待安装ESXi 5.5的机器需要大于2GB以上内存,并且支持64位和虚拟化. 下载:VMware-VMvisor-Installer-5.5 ...