这套题比较烂。。。

上来看到T2是原题,一想上一次考试遇到原题就不换,这次应该也是,于是直接开始码,码了一半然后换题了

T1打表找规律或者推式子都不难。。。

T2水的一匹暴力剪枝即可,但是我并不知道数据那么那么水所以还花了很多时间优化

T3神奇的大模拟,挺有意思但是考场上不可能有人能拿到20+

所以因为题比较烂,所以我就上去了?

隔了一场之后RP守恒又恢复了?

啊啊不要乱说啊再过十几分钟就又要考一场了啊。。。

T1:木板

具体化式子也就是个初中数学,结论就是(最大平方因子的平方根-1)<<3,打个100的表就出来了

 #include<cstdio>
int main(){
long long n,mx;scanf("%lld",&n);
while(n){
for(long long i=;i*i<=n;++i)if(n%(i*i)==)mx=i;
printf("%lld\n",(mx-)<<);scanf("%lld",&n);
}
}

183B

T2:打扫卫生

看到数据范围,直接上根号。

dp[i]表示以i为某一段的结尾,到i为止的最优dp值。

几个比较明显的性质:

0)$dp[i]<=i$

1)颜色数超过$\sqrt{i}$时不必再考虑从前面转移。否则转移来的值不满足上一条

2)任意$i<j$有$dp[i]<=dp[j]$

运用第二条打一个暴力,及时跳出。

 #include<cstdio>
#include<iostream>
using namespace std;
int dp[],n,m,a[],al[],cal;
int min(int a,int b){return a<b?a:b;}
int main(){//freopen("2.in","r",stdin);freopen("bl.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=;i<=n;++i){scanf("%d",&a[i]);if(a[i]==a[i-])i--,n--;}
for(int i=;i<=n;++i)dp[i]=i;
for(int i=;i<=n;++i){
int knd=;
for(int j=i-;~j;--j){cal++;
knd+=al[a[j+]]==i?:;
if(knd*knd>=dp[i])break;
al[a[j+]]=i;
dp[i]=min(dp[i],dp[j]+knd*knd);
}
}printf("%d\n",dp[n]);std:cerr<<cal<<endl;
}

800ms

然后你就AC了。

显然复杂度还是$O(n^2)$的。对拍随机数据,其最内层循环进入了900000000次。

可见题目的数据还不如随机数据。

优化,上述做法的复杂度瓶颈在于你只保证了你扫了$\sqrt{i}$个颜色,但不一定是$\sqrt{i}$个位置。

那么其实可以发现,从i往前扫,到连续的一段区间上的颜色数都相等,根据那第2条性质,那么你直接从这个区间的左端点转移即可。

那么现在的问题是:你要O(1)找到从位置i往前最远到哪里有恰好k种颜色。

考虑位置i,它的颜色为p,那么你找到上一次p出现的位置,这个位置以后再也不会贡献颜色数了,以后不会从它转移。

那么很自然的想法就是一个链表,把上一个p跳过,这一个p加入。

这样沿着链表往前跳,每次必然遇到一个新颜色,颜色数+1。

根据性质1,你最多跳$\sqrt{i}$种颜色。

总复杂度$n\sqrt{n}$。

 #include<cstdio>
int dp[],n,m,a[],lp[],lst[],nxt[];
int min(int a,int b){return a<b?a:b;}
int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;++i){scanf("%d",&a[i]);if(a[i]==a[i-])i--,n--;}
for(int i=;i<=n;++i)dp[i]=i;
lst[]=;nxt[]=;
for(int i=;i<=n;++i){
int knd=,l=lp[a[i]];
lp[a[i]]=i;
if(l)lst[nxt[l]]=lst[l],nxt[lst[l]]=nxt[l];
nxt[lst[]]=i,lst[i]=lst[],lst[]=i,nxt[i]=;
for(int j=lst[];j;j=lst[j]){
knd++;
if(knd*knd>=dp[i])break;
dp[i]=min(dp[i],dp[lst[j]]+knd*knd);
}
}printf("%d\n",dp[n]);
}

T3:骆驼

大模拟。

结论是5*5的网格任意选取起点终点都有解。

所以把这些5*5网格拼接一下就好了。

分奇偶讨论,有些人需要特判5和15的点。

最好好好利用关键位置(3,3),能简单不少(但是我用的不是。。所以特别麻烦)

大网格的拼接也可以搜索,不一定要执迷于for循环自行讨论。。。

终于打出来了!

 #include<cstdio>
int n,s[][][][][][],ans[][],sx,sy,ex,ey,ord[][];
const int xx[]={,,,-,,,-,-};
const int yy[]={,-,,,,-,,-};
#define tx x+xx[i]
#define ty y+yy[i]
bool sch(int stp,int x,int y){
if(stp==)return x==ex&&y==ey;
if(x==ex&&y==ey)return false;
for(int i=;i<=;++i)if(tx>&&ty>&&tx<=&&ty<=&&!s[sx][sy][ex][ey][tx][ty]){
s[sx][sy][ex][ey][tx][ty]=stp+;
if(sch(stp+,tx,ty))return true;
s[sx][sy][ex][ey][tx][ty]=;
}return false;
}
void fill(int x,int y,int sx,int sy,int ex,int ey){
for(int i=;i<=;++i)for(int j=;j<=;++j)ans[x*-+i][y*-+j]=s[sx][sy][ex][ey][i][j]++*ord[x][y];
}
int main(){scanf("%d",&n);
for(int i=;i<=;++i)for(int j=;j<=;++j)for(int k=;k<=;++k)for(int l=;l<=;++l)
s[sx=i][sy=j][ex=k][ey=l][i][j]=,sch(,i,j);
int bl=n/;
if(bl==)for(int i=;i<=;++i)for(int j=;j<=;++j)ans[i][j]=s[][][][][i][j];
else if(bl==){
for(int i=;i<=;++i)for(int j=;j<=;++j)ans[i][j]=s[][][][][i][j]>?n*n-+s[][][][][i][j]:s[][][][][i][j];//(1,1)
ord[][]=;ord[][]=;ord[][]=;
ord[][]=;ord[][]=;ord[][]=;ord[][]=;
fill(,,,,,);fill(,,,,,);fill(,,,,,);fill(,,,,,);fill(,,,,,);
fill(,,,,,);fill(,,,,,);fill(,,,,,);
}
else if(bl&){int alc=-;
for(int i=;i<=bl;++i)ord[i][]=++alc;
for(int i=bl;i>;--i)if(i&)for(int j=;j<=bl;++j)ord[i][j]=++alc;
else for(int j=bl;j>;--j)ord[i][j]=++alc;
ord[][bl]=++alc;ord[][bl]=++alc;
for(int i=bl-;i>;--i)if(i&)ord[][i]=++alc,ord[][i]=++alc;
else ord[][i]=++alc,ord[][i]=++alc;
for(int i=;i<bl;++i)fill(i,,,,,);
fill(bl,,,,,);
for(int i=;i<=;++i)for(int j=;j<=;++j)ans[i][j]=s[][][][][i][j]>?n*n-+s[][][][][i][j]:s[][][][][i][j];//(1,1)
for(int i=;i<=bl;i+=)for(int j=;j<=bl;++j)fill(i,j,,,,);
for(int i=;i<=bl;i+=)for(int j=;j<=bl;++j)fill(i,j,,,,);
for(int i=;i<bl-;i+=)fill(,i,,,,),fill(,i,,,,);
for(int i=;i<bl;i+=)fill(,i,,,,),fill(,i,,,,);
fill(,bl,,,,);fill(,bl,,,,);fill(,bl-,,,,);fill(,,,,,);fill(,bl-,,,,);
}else{int alc=-;
for(int i=;i<=bl;++i)ord[i][]=++alc;
for(int i=bl;i;--i)if(i&)for(int j=bl;j>;--j)ord[i][j]=++alc;
else for(int j=;j<=bl;++j)ord[i][j]=++alc;
for(int i=;i<bl;++i)fill(i,,,,,);
fill(bl,,,,,);
for(int i=;i<=;++i)for(int j=;j<=;++j)ans[i][j]=s[][][][][i][j]>?n*n-+s[][][][][i][j]:s[][][][][i][j];//(1,1)
for(int i=;i<=bl;i+=)for(int j=;j<=bl;++j)fill(i,j,,,,);
for(int i=;i<=bl;i+=)for(int j=;j<=bl;++j)fill(i,j,,,,);
}
for(int i=;i<=n;++i,puts(""))for(int j=;j<=n;++j)printf("%3d ",ans[i][j]);
}

最新文章

  1. iOS 解压打包静态库命令
  2. IIS支持解析json
  3. ADO.NET基础02
  4. Token验证失败
  5. java service wrapper 级别为info导致内存剧增直至溢出
  6. Ubuntu Server上的LVM配置
  7. 阿里云容器服务--配置自定义路由服务应对DDOS攻击
  8. Java接口修饰符详解
  9. 转:nginx防DDOS攻击的简单配置
  10. Objective-C NSObject 的实现分析(2014-10-23更新)
  11. ThinkPad E530 Fedora 20 无线上网问题
  12. MVC5 EF6 Bootstrap3 HtmlHelper
  13. EXT 可选择图片列表的表单控件实现
  14. linux 写U盘出现的问题
  15. SQL SERVER 索引名前缀代表的意思
  16. c# ef 排序字段动态,构建动态Lambda和扩展方法OrderBy
  17. [转]dd命令、cp命令详解+dd命令、cp命令对比 ---delong
  18. 10分钟开发 GPS 应用,了解一下
  19. Windows 10 Version 1803 (Updated March 2018) MSDN 镜像下载
  20. C# 可指定并行度任务调度器

热门文章

  1. Docker 学习笔记之 核心概念
  2. Hexo 博客快速整合gitalk组件,给静态博客添加动态评论功能!
  3. python编程基础之三十七
  4. Linux 命令之 chmod
  5. ubuntu下安装及配置git的方法
  6. 一次SSM项目记录
  7. Flask中的渲染变量
  8. Jenkins节点配置
  9. Git上传到gitlab现有分支
  10. Chrome常见黑客插件及用法