3671: [Noi2014]随机数生成器
2015-12-17 14:59
435 查看
其实这题真的很水。。。。。。一眼就能看出来解法。
但是
但是
但是
坑~坑~坑~坑~坑~坑啊。
首先模拟一遍出变换后的排列,时间O(N*M+Q),扫一遍排列,用x[i],y[i]记录排列中值为i的数在棋盘的(x[i],y[i])的位置,然后从1开始枚举,每次判断该数能否放在路径序列里,贪心一遍就可以了。
然而这里有两个坑:
①不能建x,y数组,三个5000*5000的数组就炸内存了,所以,设rank[i]为在排列T中值为i的数的下标,然后通过下标算出x,y。
②判断该数能否放在路径序列里,要判断两点,即该数在棋盘左下方不能有数(之前放上去的数),在右上方也不行,然后这里我很SX地用树状数组去算左下和右上有多少个数,O(N*M*logN*M)果断TLE了。其实直接暴力就可以了,每次在棋盘上放一个数的时候更新它的影响,即棋盘上不能再放数的位置。
这样就变成了O(N*M*N*M),Σ( ° △ °|||)︴好像有什么不对的地方。
哦对,加一个剪枝,在更新的时候如果该行(该列)不能更新,直接退出,因为更新的矩形必定是连续且一直到尽头的,所以这判断了后面的矩形有木有被更新,于是就变成了O(N*M)。
然后就过了。33秒多。。。。。。。。不过代码好短啊
但是
但是
但是
坑~坑~坑~坑~坑~坑啊。
首先模拟一遍出变换后的排列,时间O(N*M+Q),扫一遍排列,用x[i],y[i]记录排列中值为i的数在棋盘的(x[i],y[i])的位置,然后从1开始枚举,每次判断该数能否放在路径序列里,贪心一遍就可以了。
然而这里有两个坑:
①不能建x,y数组,三个5000*5000的数组就炸内存了,所以,设rank[i]为在排列T中值为i的数的下标,然后通过下标算出x,y。
②判断该数能否放在路径序列里,要判断两点,即该数在棋盘左下方不能有数(之前放上去的数),在右上方也不行,然后这里我很SX地用树状数组去算左下和右上有多少个数,O(N*M*logN*M)果断TLE了。其实直接暴力就可以了,每次在棋盘上放一个数的时候更新它的影响,即棋盘上不能再放数的位置。
这样就变成了O(N*M*N*M),Σ( ° △ °|||)︴好像有什么不对的地方。
哦对,加一个剪枝,在更新的时候如果该行(该列)不能更新,直接退出,因为更新的矩形必定是连续且一直到尽头的,所以这判断了后面的矩形有木有被更新,于是就变成了O(N*M)。
然后就过了。33秒多。。。。。。。。不过代码好短啊
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=5000+5; typedef long long ll; int n,m,ans[N*2],rank[N*N],T ; int a,b,c,d; void add(int x,int y){ for(int i=x+1;i<=n;i++){ bool flag=true; for(int j=y-1;j>=1;j--) if(T[i][j])break; else{ T[i][j]=1; flag=false; } if(flag)break; } for(int i=x-1;i>=1;i--){ bool flag=true; for(int j=y+1;j<=m;j++) if(T[i][j])break; else{ T[i][j]=1; flag=false; } if(flag)break; } } inline int f(ll x){ return (a*x*x+b*x+c)%d; } inline int x(int s){ return (s-1)/m+1; } inline int y(int s){ return (s-1)%m+1; } int main(){ int last,q,u,v;scanf("%d%d%d%d%d%d%d%d",&last,&a,&b,&c,&d,&n,&m,&q); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)T[i][j]=(i-1)*m+j; for(int i=1;i<=n*m;i++){ u=i;v=f(last)%i+1; swap(T[x(u)][y(u)],T[x(v)][y(v)]); last=f(last); } while(q--){ scanf("%d%d",&u,&v); swap(T[x(u)][y(u)],T[x(v)][y(v)]); } for(int i=1;i<=n*m;i++)rank[T[x(i)][y(i)]]=i; int cnt=0; memset(T,0,sizeof(T)); for(int i=1;i<=n*m;i++){ if(!T[x(rank[i])][y(rank[i])]){ ans[++cnt]=i; add(x(rank[i]),y(rank[i])); if(cnt==n+m-1)break; } } for(int i=1;i<=cnt;i++) if(i!=1)printf(" %d",ans[i]); else printf("%d",ans[i]); return 0; }
相关文章推荐
- 设置radioButton的值为隐藏,文本不隐藏,后台可获取
- 山东省第六届蓝桥杯 ///标题:星系炸弹//c/c++组
- Jquery EasyUI 弹出div对话框引入其他页面(iframe)
- Spring框架之TimerTask使用
- Jquery EasyUI 弹出div对话框引入其他页面(iframe)
- HDU 2709 DP
- 360浏览器 ajax no transport
- mac yosemite 卸载java
- 【jQuery】调用live()方法绑定元素的事件
- Junit
- 利用sendmsg和recvmsg来指定发送接口或者获取接收数据接口
- [解决] [centOS] g++ 带 -static 参数编译时,报错 /usr/bin/ld: cannot find -lm
- UA模拟
- stringstream的状态如何影响数据交互
- OpenCv高斯,中值,均值,双边滤波
- 在spring的aop中获取自定义注解的参数值,即在切面中获取annotation的参数值
- 扫描条码不能触发事件
- openssl RSA 生成公钥和秘钥
- Java生成XML时,换行和缩进
- 如何启动另外一个应用的任意Activity