期望得分: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<cstdio> #include<algorithm> 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<lim-cnt) return; if(now==n+1) { for(int i=1;i<=n;++i) has[i]=has[i-1]*10+a[i]; int sum=0; for(int len=1;len<=n;++len) { for(int i=1;i+len-1<=n;++i) b[i]=has[i+len-1]-has[i-1]*Pow(10,len); sort(b+1,b+n+1-len+1); for(int i=1;i+len-1<=n;++i) if(b[i]!=b[i-1]) sum++; } if(sum==m) f[lim]++; return; } for(int i=1;i<=cnt;++i) a[now]=i,dfs(now+1,cnt,lim); a[now]=cnt+1; dfs(now+1,cnt+1,lim); } int getC(int x,int y) { int sum=1; for(int i=x-y+1;i<=x;++i) sum=1LL*sum*i%mod; for(int i=1;i<=y;++i) sum=1LL*sum*inv[i]%mod; return sum; } int pow(int a,int b) { int res=1; for(;b;a=1LL*a*a%mod,b>>=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); }
考场80分找规律代码
#include<cstdio> #include<iostream> 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 || m>n*(n+1)/2) cout<<0; else if(n==m) cout<<k; else if(m==n*(n+1)/2) { LL sum=k; for(int i=1;i<n;++i) sum=sum*(k-i)%mod; cout<<sum; } else if(n==2) cout<<(LL)k*(k-1)/2%mod; else if(n==3) { if(m==4) cout<<'0'; else if(m==5) cout<<(LL)k*(k-1)%mod*3%mod; } else if(n==4) { if(m==5 || m==6) cout<<0; else if(m==7) cout<<(LL)k*(k-1)%mod*3%mod; else if(m==8) cout<<(LL)k*(k-1)%mod*4%mod; else if(m==9) cout<<(LL)k*(k-1)%mod*(k-2)%mod*6%mod; } else if(n==5) { if(m<=8) cout<<0; else if(m==9) cout<<(LL)k*(k-1)%mod*3%mod; else if(m==10) cout<<0; else if(m==11) cout<<(LL)k*(k-1)%mod*10%mod; else if(m==12) cout<<(LL)k*(k-1)%mod*2%mod*((k-2)*3%mod+1)%mod; else if(m==13) cout<<(LL)k*(k-1)%mod*(k-2)%mod*19%mod; else if(m==14) cout<<(LL)k*(k-1)%mod*(k-2)%mod*(k-3)%mod*10%mod; } else if(n==6) { if(m<=10) cout<<0; else if(m==11) cout<<(LL)k*(k-1)%mod*3%mod; else if(m==12 || m==13) cout<<0; else if(m==14) cout<<(LL)k*(k-1)%mod*10%mod; else if(m==15) cout<<(LL)k*(k-1)%mod*3%mod*(2*k-1)%mod; else if(m==16) cout<<(LL)k*(k-1)%mod*9%mod; else if(m==17) cout<<(LL)k*(k-1)%mod*(k-2)%mod*45%mod; else if(m==18) cout<<(LL)k*(k-1)%mod*(k-2)%mod*((k-1)*10%mod+19)%mod; else if(m==19) cout<<(LL)k*(k-1)%mod*(k-2)%mod*(k-3)%mod*55%mod; else if(m==20) cout<<(LL)k*(k-1)%mod*(k-2)%mod*(k-3)%mod*(k-4)%mod*15%mod; } else if(n==7) { if(m!=27) cout<<0; else cout<<(LL)k*(k-1)%mod*(k-2)%mod*(k-3)%mod*(k-4)%mod*(k-5)%mod*21%mod; } else if(n==8) { if(m!=35) cout<<0; else cout<<(LL)k*(k-1)%mod*(k-2)%mod*(k-3)%mod*(k-4)%mod*(k-5)%mod*(k-6)%mod*28%mod; } else if(n==9) { if(m!=44) cout<<0; else cout<<(LL)k*(k-1)%mod*(k-2)%mod*(k-3)%mod*(k-4)%mod*(k-5)%mod*(k-6)%mod*(k-7)%mod*36%mod; } else if(n==10) { if(m!=54) cout<<0; else cout<<(LL)k*(k-1)%mod*(k-2)%mod*(k-3)%mod*(k-4)%mod*(k-5)%mod*(k-6)%mod*(k-7)%mod*(k-8)%mod*45%mod; } }
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<queue> #include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> 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<node>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<<ncol[i][j]]=val[i][j]; int S=1<<k; for(int s=1;s<S;++s) { for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) { for(int t=(s-1)&s;t;t=(t-1)&s) dp[i][j][s]=min(dp[i][j][s],dp[i][j][t]+dp[i][j][s^t]-val[i][j]); if(dp[i][j][s]<oo) q.push(node(i,j)),vis[i][j]=true; } spfa(s); } for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) ans=min(ans,dp[i][j][S-1]); } int main() { freopen("graph.in","r",stdin); freopen("graph.out","w",stdout); srand(1000); int tot=0; read(n); read(m); read(k); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) read(col[i][j]),tot=max(tot,col[i][j]); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) read(val[i][j]); int T=300; tot++; for(int i=0;i<tot;++i) a[i]=i; while(T--) { random_shuffle(a,a+tot); for(int i=0;i<k;++i) mp[a[i]]=i; for(int i=k;i<tot;++i) mp[a[i]]=rand()%k; for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) if(col[i][j]==-1) ncol[i][j]=-1; else ncol[i][j]=mp[col[i][j]]; Steiner(); } printf("%d",ans); }
期望80实际70暴力
说好的不包括-1呢。。。
不过没判-1拿了30里面的20,这数据准是随机的。。。
#include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define N 16 int 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<k) return; ans=min(ans,cnt); } void dfs(int x,int y) { if(y==m+1) { if(x==n) { judge(); return; } dfs(x+1,1); return; } dfs(x,y+1); use[x][y]=true; dfs(x,y+1); use[x][y]=false; } void work() { ans=2e9; dfs(1,1); cout<<ans; } } namespace force2 { int ans; void dfs(int now,int endd,int type,int color,int cost) { if(now==endd+1) { if(ok(color)) ans=min(ans,cost); return; } int ncolor,ncost; if(col[1][now]!=-1 && col[2][now]!=-1) { ncolor=color|(1<<col[1][now])|(1<<col[2][now]); ncost=cost+val[1][now]+val[2][now]; dfs(now+1,endd,0,ncolor,ncost); } if((!type || type==1) && col[1][now]!=-1) { ncolor=color|(1<<col[1][now]); ncost=cost+val[1][now]; dfs(now+1,endd,1,ncolor,ncost); } if((!type || type==2) && col[2][now]!=-1) { ncolor=color|(1<<col[2][now]); ncost=cost+val[2][now]; dfs(now+1,endd,2,ncolor,ncost); } } void work() { ans=2e9; for(int i=1;i<=m;++i) for(int j=i;j<=m;++j) dfs(i,j,0,0,0); cout<<ans; } } namespace force3 { int f[N][N][1024]; struct node { int x,y; node(int x_=0,int y_=0) : x(x_),y(y_) { } }; queue<node>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]<f[nx][ny][s]) { f[nx][ny][s]=f[now.x][now.y][s]+val[nx][ny]; if(!vis[nx][ny]) q.push(node(nx,ny)),vis[nx][ny]=true; } } } } void work() { for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) col[i][j]=first[col[i][j]]; memset(f,63,sizeof(f)); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) f[i][j][1<<col[i][j]]=val[i][j]; int S=1<<num; int oo=f[0][0][0]; for(int s=1;s<S;++s) { for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) { for(int t=s-1;t;t=(t-1)&s) f[i][j][s]=min(f[i][j][s],f[i][j][t]+f[i][j][s^t]-val[i][j]); if(f[i][j][s]<oo) q.push(node(i,j)),vis[i][j]=true; } spfa(s); } int ans=2e9; for(int s=1;s<S;++s) if(ok(s)) { for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) ans=min(ans,f[i][j][s]); } cout<<ans; } } int main() { freopen("graph.in","r",stdin); freopen("graph.out","w",stdout); init(); if(n<=4 && m<=4 && k<=4) force1::work(); else if(n<=2 && m<=15) force2::work(); else force3::work(); }
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<cstdio> #include<cstring> using namespace std; typedef long long LL; const int mod=1e9+7; #define N 101 LL 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<k) { if(b0[k1]-a0[k1]==c0[k1]-b0[k1]) break; if(b0[k1]-a0[k1]<c0[k1]-b0[k1]) { k1++; a0[k1]=b0[k1-1]; b0[k1]=2*b0[k1-1]-a0[k1-1]; c0[k1]=c0[k1-1]; } else { k1++; a0[k1]=a0[k1-1]; b0[k1]=2*b0[k1-1]-c0[k1-1]; c0[k1]=b0[k1-1]; } } while(k2<k) { if(y0[k2]-x0[k2]==z0[k2]-y0[k2]) break; if(y0[k2]-x0[k2]<z0[k2]-y0[k2]) { k2++; x0[k2]=y0[k2-1]; y0[k2]=2*y0[k2-1]-x0[k2-1]; z0[k2]=z0[k2-1]; } else { k2++; x0[k2]=x0[k2-1]; y0[k2]=2*y0[k2-1]-z0[k2-1]; z0[k2]=y0[k2-1]; } } int l1,l2; bool tag=false; for(l1=0;l1<=k1 && !tag;++l1) for(l2=0;l2<=k2 && !tag;++l2) if(a0[l1]==x0[l2] && b0[l1]==y0[l2] && c0[l1]==z0[l2]) tag=true; l1--; l2--; memset(f,-1,sizeof(f)); printf("%d",dfs(l1,l2,k)); }
考场爆零原因:用%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%的算法就不可能成为正解了?在大量的操作下,错误率大大的降低。要注重一些非完美算法,也多思考一些非完美的解题思路(毕竟目前对我来说省选及以上难度比赛中想出正解的概率是很小的),不一定非要是有名字的算法呀!!