博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
清北学堂2018年1月省选强化班模拟考试2
阅读量:6209 次
发布时间:2019-06-21

本文共 9408 字,大约阅读时间需要 31 分钟。

期望得分:40+80+30=150

实际得分:80+70+0=150

 

T1

LYK loves string(string)

Time Limit:1000ms   Memory Limit:128MB

 

题目描述

LYK喜欢字符串,它认为一个长度为n的字符串一定会有n*(n+1)/2个子串,但是这些子串是不一定全部都不同的,也就是说,不相同的子串可能没有那么多个。LYK认为,两个字符串不同当且仅当它们的长度不同或者某一位上的字符不同。LYK想知道,在字符集大小为k的情况下,有多少种长度为n的字符串,且该字符串共有m个不相同的子串。

由于答案可能很大,你只需输出答案对1e9+7取模后的结果即可。

 

输入格式(string.in)

一行3个数n,m,k。

 

输出格式(string.out)

    一行,表示方案总数。

 

输入样例

2 3 3

 

输出样例

6

 

样例解释

共有6种可能,分别是ab,ac,ba,bc,ca,cb。

 

数据范围

对于20%的数据:1<=n,k<=5。

对于40%的数据:1<=n<=5,1<=k<=1000000000。

对于60%的数据:1<=n<=8,1<=k<=1000000000。

对于100%的数据:1<=n<=10,1<=m<=100,1<=k<=1000000000。

 

Hint

本题非常easy。

 

k再大也没有用,最多就用n种字符,最后乘个组合数即可

搜索出用i(i<=n)种字符,有m种不同子串的字符串的个数 f[i]

ans= Σ f[i]*C(k,i)

 

搜索的时候每次只往后扩增一个新字母

即 若当前字母为i,下一个字母的范围为[1,i+1]

设字符集大小为S

这样对于搜出的每种方案 * S的阶乘 即为 用 S 种 字符的答案

 

判断一个字符串内有多少种不同的字串时,用哈希

 

#include
#include
using namespace std;typedef long long LL;const int mod=1e9+7;int n,m;int a[11];LL has[11],b[11];int f[11]; int inv[11];LL Pow(LL a,int b){ LL res=1; for(;b;a*=a,b>>=1) if(b&1) res*=a; return res;}void dfs(int now,int cnt,int lim){ if(cnt>lim || n-now+1
>=1) if(b&1) res=1LL*res*a%mod; return res;}int main(){ freopen("string.in","r",stdin); freopen("string.out","w",stdout); int k; scanf("%d%d%d",&n,&m,&k); int t=min(n,k); for(int i=1;i<=t;++i) dfs(1,0,i); LL bit=1; for(int i=1;i<=t;++i) { inv[i]=pow(i,mod-2); bit*=i; f[i]=f[i]*bit%mod; } int ans=0; for(int i=1;i<=t;++i) ans=(ans+1LL*f[i]*getC(k,i)%mod)%mod; printf("%d",ans); }
View Code

 

考场80分找规律代码

#include
#include
using namespace std;const int mod=1e9+7;typedef long long LL;int main(){ freopen("string.in","r",stdin); freopen("string.out","w",stdout); int n,m,k; scanf("%d%d%d",&n,&m,&k); if(m
n*(n+1)/2) cout<<0; else if(n==m) cout<
View Code

 

T2

LYK loves graph(graph)

Time Limit:2000ms   Memory Limit:128MB

 

题目描述

LYK喜欢花花绿绿的图片,有一天它得到了一张彩色图片,这张图片可以看做是一张n*m的网格图,每个格子都有一种颜色去染着,我们用-1至n*m-1来表示一个格子的颜色。特别地,-1代表这个颜色是黑色,LYK不喜欢黑色!

LYK想将剪下这张图片中的一张子图片来(四联通块),使得这个子图片不存在黑色的格子,并且至少有k个不同的颜色。

但是每个格子有自己的脾气,特别的,第i行第j列这个格子如果被LYK选中了,LYK需要花费相应的代价。LYK想花费尽可能少的代价来剪下一张满足自己要求的图片。

 

输入格式(graph.in)

    第一行三个整数,n,m,k.

    接下来n行,每行m个数,表示图片中每个格子的颜色,每个数在-1到n*m-1之间。

  接下来n行,每行m个数,表示选择每个位置所需要的代价。

 

输出格式(graph.out)

一行,表示最小代价和。

 

输入样例

3 3 3

0 0 1

2 3 3

-1 2 1

3 1 5

4 10 1

9 3 4

 

输出样例

7

 

数据范围

对于20%的数据:1<=n,m,k<=4。

对于另外30%的数据:不同的颜色数<=10(不包括-1)。

对于再另外30%的数据:1<=n<=2,1<=m<=15。

对于100%的数据:1<=n,m<=15,1<=k<=7,1<=ai,j<=100000。

数据保证一定有解。

 

听到标算的我一口老血喷了出来。。。

 

首先这题肯定是斯坦纳树(除非你想写插头DP)

但是颜色总数高达225种,没法状态压缩

但是询问只要求有7种颜色,所以就可以大开脑洞:

 

把225种颜色随机映射成7种颜色,然后做斯坦纳树!!!

 

我们来分析分析它的正确率:

首先可以肯定的是我们算出的答案只会大于等于最优解

因为原本不同的颜色可能被随机映射为相同的颜色,原本相同的颜色随机映射后一定不同

对于最优解中的7种颜色来说,

每种颜色都有7种映射方案,所以一共有7^7种映射方案

而只有这7种颜色映射玩之后还是7种颜色,才有可能算出最优解,这种情况一共有 7! 种

所以随机映射做斯坦纳树一次 的 正确率 为 7!/  7^7  ≈ 0.006 = 0.6% 

错误率=99.4%

那么如果随机映射做斯坦纳树T次,错误率就是 99.6%  ^ T 

如果T=400,错误率 ≈ 9%

那么正确率  = 91%

你还可以再多做几遍,正确率还是蛮高的。。。。。。

 

#include
#include
#include
#include
#include
#include
using namespace std;#define N 16 int n,m,k;int col[N][N],val[N][N];int a[N*N],mp[N*N];int ncol[N][N];int dp[N][N][1<<7];struct node{ int x,y; node(int x=0,int y=0):x(x),y(y) {}};queue
q;bool vis[N][N];int dx[4]={-1,0,1,0};int dy[4]={ 0,1,0,-1};int ans=2e9;void read(int &x){ x=0; int f=1; char c=getchar(); while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); } while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } x*=f;}void spfa(int s){ node now; int sx,sy,nx,ny; while(!q.empty()) { now=q.front(); q.pop(); sx=now.x; sy=now.y; vis[sx][sy]=false; for(int i=0;i<4;++i) { nx=sx+dx[i]; ny=sy+dy[i]; if(nx<=0 || nx>n || ny<=0 || ny>m || ncol[nx][ny]==-1) continue; if(dp[nx][ny][s]>dp[sx][sy][s]+val[nx][ny]) { dp[nx][ny][s]=dp[sx][sy][s]+val[nx][ny]; if(!vis[nx][ny]) q.push(node(nx,ny)),vis[nx][ny]=true; } } }}void Steiner(){ memset(dp,63,sizeof(dp)); int oo=dp[0][0][0]; for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) if(ncol[i][j]!=-1) dp[i][j][1<
View Code

 

期望80实际70暴力

说好的不包括-1呢。。。

不过没判-1拿了30里面的20,这数据准是随机的。。。

#include
#include
#include
#include
#include
using namespace std;#define N 16int n,m,k;int col[16][16],val[16][16];bool tag;int num,first[N*N];int dx[4]={-1,0,1,0};int dy[4]={
0,1,0,-1};void read(int &x){ x=0; int f=1; char c=getchar(); while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); } while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } x*=f;}void init(){ read(n); read(m); read(k); memset(first,-1,sizeof(first)); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) { read(col[i][j]); if(col[i][j]==-1) tag=true; else if(first[col[i][j]]==-1) first[col[i][j]]=num++; } for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) read(val[i][j]);}bool inmap(int x,int y){ if(!x || !y || x>n || y>m) return false; return true;}bool ok(int s){ int cnt=0; for(int i=1,bit=1;i<=30;++i,bit<<=1) cnt+=bool(s&bit); return cnt>=k;}namespace force1{ bool use[5][5]; bool vis[5][5]; int sum,ans; bool use_col[N*N]; void dfs2(int x,int y) { sum++; vis[x][y]=true; int nx,ny; for(int i=0;i<4;++i) { nx=x+dx[i]; ny=y+dy[i]; if(inmap(nx,ny) && !vis[nx][ny] && use[nx][ny]) dfs2(nx,ny); } } bool connect() { int sx=0,sy=0,tot=0; for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) if(use[i][j]) { tot++; if(!sx) sx=i,sy=j; } sum=0; memset(vis,false,sizeof(vis)); dfs2(sx,sy); return sum==tot; } void judge() { if(!connect()) return; int cnt=0,ccnt=0; memset(use_col,0,sizeof(use_col)); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) if(use[i][j]) { if(col[i][j]==-1) return; cnt+=val[i][j]; if(!use_col[col[i][j]]) { use_col[col[i][j]]=true; ccnt++; } } if(ccnt
q; bool vis[N][N]; void spfa(int s) { node now; int nx,ny; while(!q.empty()) { now=q.front(); q.pop(); vis[now.x][now.y]=false; for(int i=0;i<4;++i) { nx=now.x+dx[i]; ny=now.y+dy[i]; if(!inmap(nx,ny)) continue; if(f[now.x][now.y][s]+val[nx][ny]
View Code

 

T3

LYK loves rabbits(rabbits)

Time limit:1000ms     Memory limit:128MB

 

题目描述

LYK喜欢兔子,它在家中养了3只兔子。

有一天,兔子不堪寂寞玩起了游戏,3只兔子排成一排,分别站在a,b,c这3个位置。

游戏的规则是这样的,重复以下步骤k次:选择两个不同的兔子A和B,假如它们位于X与Y,A可以从X跳到Y+Y-X处,但是跳跃时是不允许一下子跳过两只兔子的,也就是说第三只兔子不在[min{X,Y+Y-X},max{X,Y+Y-X}]处。

现在3只小兔子的位置分别到了x,y,z(3只兔子长得一样,即三只兔子跳完之后的顺序可以变化)处,但是它们忘记一开始是怎么跳的了,想让你帮它们还原跳法。但这个问题非常easy,于是LYK要求你输出方案总数。

保证答案有解。

由于答案巨大,你只需输出答案对1e9+7取模后的结果就可以了。

 

输入格式(rabbits.in)

第一行3个数a,b,c。

第二行3个数x,y,z。

第三行一个数k。

数据保证3只兔子的起始位置a,b,c严格递增且3只兔子最终的位置x,y,z严格递增。

 

输出格式(rabbits.out)

一行表示方案总数。

 

输入样例1

0 2 5

0 2 5

2

 

输出样例1

3

 

输入样例2

0 2 4

0 2 4

2

 

输出样例2

2

 

样例解释

对于样例1:共有3种跳法,第一次跳完后的位置分别是{0,-2,5},{4,2,5},{0,8,5}。

 

数据范围

对于10%的数据k=1。J

对于30%的数据k<=10。

对于另外20%的数据a=x,b=y,c=z。

对于再另外20%的数据a-b=b-c。

对于再再另外20%的数据a,b,c与x,y,z之间不超过10步可达。

对于100%的数据k<=100,|a|,|b|,|c||x|,|y|,|z|<=10^18。

 

如果能由外往里跳,那么只能跳一个

中间那个可以往外跳,有向左和向右两种方式

所以跳的路径是一棵二叉树

设起始位置在A号节点,终止位置在B号节点

令f[i][j][k] 表示A 和 LCA的距离为i,B 和 LCA的距离为j,还剩下k步可以跳的方案数

一、对于一般的一对A和B(不在根节点,且LCA不是A或B)来说,有两种决策:

1、A向上跳,跳到 i-1 j  k-1

2、A向下跳,A往左往右跳一个样,跳到 i+1 j k-1,方案数*2

二、若A是LCA

如果B也是LCA,即A和B在同一个位置,那可以

1、A往上跳,跳到 i j+1 k-1

2、A往下跳,跳到 i+1 j k-1 方案数*2

如果B不是LCA,

1、A往上跳,跳到 i j+1 k-1

2、A往下跳,跳到非B所在的子树 i+1 j k-1;跳到B所在的子树 i j-1 k-1

注意,A有可能是二叉树的根节点,这样A不能向上跳

此时i=0,j>B的深度,特判这种情况

 

#include
#include
using namespace std;typedef long long LL;const int mod=1e9+7;#define N 101LL a0[N],b0[N],c0[N];LL x0[N],y0[N],z0[N];int f[N][N][N];int k1,k2;int dfs(int i,int j,int k){ if(!i && !j && !k) return 1; if(i+j>k) return 0; if(!i && j>k2) return 0; if(f[i][j][k]!=-1) return f[i][j][k]; if(!i) { if(!j) f[i][j][k]=(dfs(0,1,k-1)+dfs(1,0,k-1)*2%mod)%mod; else f[i][j][k]=((dfs(0,j+1,k-1)+dfs(0,j-1,k-1))%mod+dfs(1,j,k-1))%mod; } else f[i][j][k]=(dfs(i-1,j,k-1)+dfs(i+1,j,k-1)*2%mod)%mod; return f[i][j][k];}int main(){ freopen("rabbits.in","r",stdin); freopen("rabbits.out","w",stdout); int k; scanf("%I64d%I64d%I64d%I64d%I64d%I64d",&a0[0],&b0[0],&c0[0],&x0[0],&y0[0],&z0[0]); scanf("%d",&k); bool root=false; while(k1
View Code

 

考场爆零原因:用%d读long long

 

Summary

1、本场考试150分虽然是rank3,但150分的有8个,T3直接输出1拿到10分就可以脱颖而出

2、考场上的一分钟都不能放弃,到了最后也要垂死挣扎,特判之类的东西全打上,多扑腾会儿

3、T1正解是搜索,我在考场上是打表找规律,只找全了n<=6的,>6的只找到了m等于能取到的最大值和次大值的规律,期望是40分,结果后面60%的数据有40%的数据m是最/次大值,这就多得了40分,考场上还觉得没有什么用犹豫了好久才打上,所以如果写的是特判之类的,不要放过任何对的idea,说不定你就判到了数据呢。(对于这种搜索题数据为梯度内极端数据可能性比较大)

4、T2暴力80分,因为实际数据与题面中的数据描述不符,拿了70分,那个正解随机性算法是当时的我无论如何也想不到的,在这种情况下,一定要拿满暴力分

5、一定要特别注意long long的读入与输出,不仅仅是lld与I64d的问题,考场上用%d读long long,自己造的小数据没有问题,测试数据全>int。这种蠢到不能再蠢得问题不能出现第二次

6、加强搜索,T1竟然没看出来是道搜索题

7、谁说随机性的、正确率不是100%的算法就不可能成为正解了?在大量的操作下,错误率大大的降低。要注重一些非完美算法,也多思考一些非完美的解题思路(毕竟目前对我来说省选及以上难度比赛中想出正解的概率是很小的),不一定非要是有名字的算法呀!!

 

转载于:https://www.cnblogs.com/TheRoadToTheGold/p/8404293.html

你可能感兴趣的文章
几种浏览器内核(百度百科)
查看>>
leetcode | Text Justification
查看>>
36、IO流概述和分类
查看>>
python知识点总结---函数
查看>>
多线程,线程池与BeginInvoke()
查看>>
【JavaScript 】for 循环进化史
查看>>
不背公式快速计算IP地址掩码---游码法
查看>>
ubuntu 14.04 安装torch及编译环境zbstudio
查看>>
JSONArray的学习理解
查看>>
闰年判断
查看>>
接口测试基础
查看>>
五种WordPress防止垃圾评论方法-过滤垃圾评论提高WP运行效率
查看>>
form表单的两种提交方式,submit和button的用法
查看>>
php采集远程文章简单类
查看>>
Android ListView的滚动条始终显示并且滚动条样式自定义
查看>>
Spring读书笔记-----Spring的Bean之设置Bean值
查看>>
1044. Shopping in Mars (25)
查看>>
ccf 地铁修建
查看>>
解决table边框圆角无效
查看>>
EasyUI的tree展开所有的节点或者根据特殊的条件控制展示指定的节点
查看>>