一般情况下,程序运行消耗时间主要与时间复杂度有关,超时与否取决于算法是否正确。

但对于某些题目,时间复杂度正确的程序也无法通过,这时我们就需要卡常数,即通过优化一些操作的常数因子减少时间消耗。

比如这道题 P5309 [Ynoi2011] 初始化

这道题目的做法我写在另一篇博客里,这里主要研究卡常方式。

#include<bits/stdc++.h>
using namespace std;
const int h=200010;
inline int read() {
int s = 0, w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-') w= -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
int mod=1e9+7;
inline void update(int &x, int y) {
x += y;
if(x >= mod) x -= mod;
} int n,m;
int a[h];
int b_sum[h];
int len;
int pre[2010][2010];
int suf[2010][2010];
int get_pos(int x){
return (x-1)/len+1;
}
int main(){
n=read(),m=read();
len=135;
for(int i=1;i<=n;i++)
a[i]=read(),update(b_sum[get_pos(i)],a[i]);
int op,x,y,z;
for(int i=1;i<=m;i++){
op=read(),x=read(),y=read();
if(op==1){
z=read();
if(x>=len)
for(int j=y;j<=n;j+=x)
update(a[j],z),update(b_sum[get_pos(j)],z);
else{
for(int j=y;j<=x;j++)
update(pre[x][j],z);
for(int j=1;j<=y;j++)
update(suf[x][j],z);
}
}
else{
int l=x,r=y,lb=get_pos(x),rb=get_pos(y);
int ans=0;
if(lb==rb)
for(int j=l;j<=r;j++)
update(ans,a[j]);
else{
for(int j=l;j<=lb*len;j++)
update(ans,a[j]);
for(int j=lb+1;j<=rb-1;j++)
update(ans,b_sum[j]);
for(int j=(rb-1)*len+1;j<=r;j++)
update(ans,a[j]); } for(int j=1;j<len;j++){
lb=(l-1)/j+1,rb=(r-1)/j+1;
if(lb==rb)
ans-=pre[j][(l-1)%j],ans%=mod,ans+=pre[j][(r-1)%j+1],ans%=mod;
else
ans=(ans+1ll*(rb-lb-1)*pre[j][j]+pre[j][(r-1)%j+1]+suf[j][(l-1)%j+1])%mod;
}
ans = ans % mod + mod;
ans = (ans >= mod) ? ans - mod : ans;
printf("%d\n",ans);
}
} return 0;
}

20分超时代码

技巧一:手写常数因子大的运算

c++中取模运算常数因子很大,于是我们改用更快的运算组合表示取模。

inline void update(int &x, int y) {
x += y;
if(x >= mod) x -= mod;
}

经此修改,可以拿到95分。

#include<bits/stdc++.h>
using namespace std;
const int h=200010;
inline int read() {
int s = 0, w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-') w= -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
int mod=1e9+7;
inline void update(int &x, int y) {
x += y;
if(x >= mod) x -= mod;
} int n,m;
int a[h];
int b_sum[h];
int len;
int pre[2010][2010];
int suf[2010][2010];
int get_pos(int x){
return (x-1)/len+1;
}
int main(){
n=read(),m=read();
len=120;
for(int i=1;i<=n;i++)
a[i]=read(),update(b_sum[get_pos(i)],a[i]);
int op,x,y,z;
for(int i=1;i<=m;i++){
op=read(),x=read(),y=read();
if(op==1){
z=read();
if(x>=len)
for(int j=y;j<=n;j+=x)
update(a[j],z),update(b_sum[get_pos(j)],z);
else{
for(int j=y;j<=x;j++)
update(pre[x][j],z);
for(int j=1;j<=y;j++)
update(suf[x][j],z);
}
}
else{
int l=x,r=y,lb=get_pos(x),rb=get_pos(y);
int ans=0;
if(lb==rb)
for(int j=l;j<=r;j++)
update(ans,a[j]);
else{
for(int j=l;j<=lb*len;j++)
update(ans,a[j]);
for(int j=lb+1;j<=rb-1;j++)
update(ans,b_sum[j]);
for(int j=(rb-1)*len+1;j<=r;j++)
update(ans,a[j]); } for(int j=1;j<len;j++){
lb=(l-1)/j+1,rb=(r-1)/j+1;
if(lb==rb)
ans-=pre[j][(l-1)%j],ans%=mod,ans+=pre[j][(r-1)%j+1],ans%=mod;
else
ans=(ans+1ll*(rb-lb-1)*pre[j][j]+pre[j][(r-1)%j+1]+suf[j][(l-1)%j+1])%mod;
}
ans = ans % mod + mod;
ans = (ans >= mod) ? ans - mod : ans;
printf("%d\n",ans);
}
} return 0;
}

95分优化取模

技巧二:块长乱搞

这道题目需要使用分块。

而分块的时间复杂度往往随着块长而剧烈波动。

于是我们不断尝试新的块长。(为了节约评测机资源可以二分寻找)

得出最优块长在135左右,通过了这道题,耗时为5.93s。

#include<bits/stdc++.h>
using namespace std;
const int h=200010;
inline int read() {
int s = 0, w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-') w= -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
int mod=1e9+7;
inline void update(int &x, int y) {
x += y;
if(x >= mod) x -= mod;
} int n,m;
int a[h];
int b_sum[h];
int len;
int pre[2010][2010];
int suf[2010][2010];
int get_pos(int x){
return (x-1)/len+1;
}
int main(){
n=read(),m=read();
len=135;
for(int i=1;i<=n;i++)
a[i]=read(),update(b_sum[get_pos(i)],a[i]);
int op,x,y,z;
for(int i=1;i<=m;i++){
op=read(),x=read(),y=read();
if(op==1){
z=read();
if(x>=len)
for(int j=y;j<=n;j+=x)
update(a[j],z),update(b_sum[get_pos(j)],z);
else{
for(int j=y;j<=x;j++)
update(pre[x][j],z);
for(int j=1;j<=y;j++)
update(suf[x][j],z);
}
}
else{
int l=x,r=y,lb=get_pos(x),rb=get_pos(y);
int ans=0;
if(lb==rb)
for(int j=l;j<=r;j++)
update(ans,a[j]);
else{
for(int j=l;j<=lb*len;j++)
update(ans,a[j]);
for(int j=lb+1;j<=rb-1;j++)
update(ans,b_sum[j]);
for(int j=(rb-1)*len+1;j<=r;j++)
update(ans,a[j]); } for(int j=1;j<len;j++){
lb=(l-1)/j+1,rb=(r-1)/j+1;
if(lb==rb)
ans-=pre[j][(l-1)%j],ans%=mod,ans+=pre[j][(r-1)%j+1],ans%=mod;
else
ans=(ans+1ll*(rb-lb-1)*pre[j][j]+pre[j][(r-1)%j+1]+suf[j][(l-1)%j+1])%mod;
}
ans = ans % mod + mod;
ans = (ans >= mod) ? ans - mod : ans;
printf("%d\n",ans);
}
} return 0;
}

100分块长优化

技巧三:按照题目内容实行特定优化

以下内容参考自原题目讨论版

不同的题目有不同的步骤,这道题里这样一个步骤耗时巨大。

for(int j=1;j<len;j++){
    lb=(l-1)/j+1,rb=(r-1)/j+1;
    if(lb==rb)
        ans-=pre[j][(l-1)%j],ans%=mod,ans+=pre[j][(r-1)%j+1],ans%=mod;
    else
        ans=(ans+1ll*(rb-lb-1)*pre[j][j]+pre[j][(r-1)%j+1]+suf[j][(l-1)%j+1])%mod;
}

这个地方运算很慢(因为一些原因套不了取模优化),而且当这个因数没有修改的时候,这些运算完全没有必要。

于是,如果这个因数没有进行修改,我们跳过后面的运算步骤。

for(int j=1;j<len;j++){
if(!pre[j][j])
continue;
lb=(l-1)/j+1,rb=(r-1)/j+1;
if(lb==rb)
ans-=pre[j][(l-1)%j],ans%=mod,ans+=pre[j][(r-1)%j+1],ans%=mod;
else
ans=(ans+1ll*(rb-lb-1)*pre[j][j]+pre[j][(r-1)%j+1]+suf[j][(l-1)%j+1])%mod;
}

以及在没有修改的情况下,弄一个前缀和,查询区间和直接调用。

耗时3.06s。

#include<bits/stdc++.h>
using namespace std;
const int h=200010;
inline int read() {
int s = 0, w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-') w= -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
int mod=1e9+7;
inline void update(int &x, int y) {
x += y;
if(x >= mod) x -= mod;
} int n,m;
int a[h];
int b_sum[h];
int len;
int pre[2010][2010];
int suf[2010][2010];
int sum[h];
int get_pos(int x){
return (x-1)/len+1;
}
int main(){
n=read(),m=read();
len=150;
for(int i=1;i<=n;i++)
a[i]=read(),update(b_sum[get_pos(i)],a[i]),update(sum[i],a[i]+sum[i-1]);
int op,x,y,z;
bool fl=0;
for(int i=1;i<=m;i++){
op=read(),x=read(),y=read();
if(op==1){
z=read();
if(x>=len)
for(int j=y;j<=n;j+=x)
fl|=1,update(a[j],z),update(b_sum[get_pos(j)],z);
else{
for(int j=y;j<=x;j++)
update(pre[x][j],z);
for(int j=1;j<=y;j++)
update(suf[x][j],z);
}
}
else{ int l=x,r=y,lb=get_pos(x),rb=get_pos(y);
int ans=0;
if(!fl) ans+=sum[r]-sum[l-1];
else
if(lb==rb)
for(int j=l;j<=r;j++)
update(ans,a[j]);
else{
for(int j=l;j<=lb*len;j++)
update(ans,a[j]);
for(int j=lb+1;j<=rb-1;j++)
update(ans,b_sum[j]);
for(int j=(rb-1)*len+1;j<=r;j++)
update(ans,a[j]); } for(int j=1;j<len;j++){
if(!pre[j][j])
continue;
lb=(l-1)/j+1,rb=(r-1)/j+1;
if(lb==rb)
ans-=pre[j][(l-1)%j],ans%=mod,ans+=pre[j][(r-1)%j+1],ans%=mod;
else
ans=(ans+1ll*(rb-lb-1)*pre[j][j]+pre[j][(r-1)%j+1]+suf[j][(l-1)%j+1])%mod;
}
ans = ans % mod + mod;
ans = (ans >= mod) ? ans - mod : ans;
printf("%d\n",ans);
}
} return 0;
}

技巧四:节约空间

开数组也是要消耗很多时间的,我们进行优化。

int b_sum[1510];
int len;
int pre[161][161];
int suf[161][161];

时间优化至3.00s。

技巧五:奇技淫巧

到这一步,接下来的卡常技巧就没有学习的必要了。

比如把mod定义成成const可以快到2.52s。

将提交语言改为c++98可以快到2.4s。

然后是...然后自己看吧,没什么意义。

(主要由@Foofish大佬贡献)

//#pragma G++ target("avx")
//#pragma G++ optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
const int h=200010;
inline int read() {
register int s = 0, w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-') w= -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
bool flag=0;
const int mod=1e9+7;
int n,m;
int a[h];
int b_sum[2010];
int len;
int pre[132][132];//pre[x][y]即modify(x,1)+modify(x,2)+...+modify(x,y)
int suf[132][132];
int sum[h];
int b_len;
int POS[201000];
#define get_pos(x) POS[x]
inline void write(int x) {
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
inline void update(int &x, int y) {
x += y;
if(x >= mod) x -= mod;
}
int main(){
//ios::sync_with_stdio(0);
n=read(),m=read();
len=130;
int Bnum = n / len;
for(int i = 1; i <= Bnum + 1; ++i)
for(int j = (i - 1) * len + 1; j <= i * len; ++j)
POS[j] = i;
for(int i=1;i<=n;i++)
a[i]=read(),update(b_sum[get_pos(i)], a[i]),update(sum[i], sum[i - 1] + a[i]);
int op,x,y,z;
for(int i=1;i<=m;i++){
op=read(),x=read(),y=read();
if(op==1){
z=read();
if(x>=len)
for(int j=y;j<=n;j+=x)
flag|=1,update(a[j], z),update(b_sum[get_pos(j)], z);
else{
for(int j=y;j<=x;j++)
update(pre[x][j], z);
for(int j=1;j<=y;j++)
update(suf[x][j], z);
}
}
else{
int l=x,r=y,lb=get_pos(x),rb=get_pos(y);
int ans=0;
if(!flag)
ans+=sum[r]-sum[l-1];
else
if(lb==rb)
for(int j=l;j<=r;j++)
update(ans, a[j]);
else{
for(int j=l;j<=lb*len;j++)
update(ans, a[j]);
for(int j=lb+1;j<=rb-1;j++)
update(ans, b_sum[j]);
for(int j=(rb-1)*len+1;j<=r;j++)
update(ans, a[j]); } for(int j=1;j<len;j++){
if(!pre[j][j])
continue;
lb=(l-1)/j+1,rb=(r-1)/j+1;
if(lb==rb) {
ans-=pre[j][(l-1)%j],ans%=mod,ans+=pre[j][(r-1)%j+1],ans%=mod;
// ans = (ans - pre[j][(l - 1) % j] + pre[j][(r - 1) % j + 1] + mod) % mod;
}
else {
ans=(ans+1ll*(rb-lb-1)*pre[j][j]+pre[j][(r-1)%j+1]+suf[j][(l-1)%j+1])%mod;
}
}
ans = ans % mod + mod;
ans = (ans >= mod) ? ans - mod : ans;
printf("%d",ans); puts("");
}
} return 0;
}

耗时2.38s

#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
template<typename T>inline void read(T& t){
int c=getchar(),f=1;t=0;
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c))t=t*10+c-48,c=getchar();t*=f;
}
template<typename T,typename ...Args>inline void read(T& t,Args&... args){
read(t),read(args...);
}

*某位大佬提供的快读,安装之后时间达到了2.23s。

目前能达到的最短时间:c++ 14 无O2优化 2.21s

#pragma G++ target("avx")
#pragma G++ optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
const int h=200010;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
template<typename T>inline void read(T& t){
int c=getchar(),f=1;t=0;
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c))t=t*10+c-48,c=getchar();t*=f;
}
template<typename T,typename ...Args>inline void read(T& t,Args&... args){
read(t),read(args...);
}
bool flag=0;
const int mod=1e9+7;
int n,m;
int a[h];
int b_sum[2010];
int len;
int pre[132][132];//pre[x][y]即modify(x,1)+modify(x,2)+...+modify(x,y)
int suf[132][132];
int sum[h];
int b_len;
int POS[201000];
#define get_pos(x) POS[x]
inline void write(int x) {
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
inline void update(int &x, int y) {
x += y;
if(x >= mod) x -= mod;
}
int main(){
//ios::sync_with_stdio(0);
read(n,m);
len=130;
int Bnum = n / len;
for(int i = 1; i <= Bnum + 1; ++i)
for(int j = (i - 1)* len + 1,ran= i * len; j <=ran ; ++j)
POS[j] = i;
for(int i=1;i<=n;i++)
read(a[i]),update(b_sum[get_pos(i)], a[i]),update(sum[i], sum[i - 1] + a[i]);
int op,x,y,z;
for(int i=1;i<=m;i++){
read(op,x,y);
if(op==1){
read(z);
if(x>=len)
for(int j=y;j<=n;j+=x)
flag|=1,update(a[j], z),update(b_sum[get_pos(j)], z);
else{
for(int j=y;j<=x;j++)
update(pre[x][j], z);
for(int j=1;j<=y;j++)
update(suf[x][j], z);
}
}
else{
int l=x,r=y,lb=get_pos(x),rb=get_pos(y);
int ans=0;
if(!flag)
ans+=sum[r]-sum[l-1];
else
if(lb==rb)
for(int j=l;j<=r;j++)
update(ans, a[j]);
else{
for(int j=l,ran=lb*len;j<=ran;j++)
update(ans, a[j]);
for(int j=lb+1;j<=rb-1;j++)
update(ans, b_sum[j]);
for(int j=(rb-1)*len+1;j<=r;j++)
update(ans, a[j]); } for(int j=1;j<len;j++){
if(!pre[j][j])
continue;
lb=(l-1)/j+1,rb=(r-1)/j+1;
if(lb==rb) {
ans-=pre[j][(l-1)%j],ans%=mod,ans+=pre[j][(r-1)%j+1],ans%=mod;
// ans = (ans - pre[j][(l - 1) % j] + pre[j][(r - 1) % j + 1] + mod) % mod;
}
else {
ans=(ans+1ll*(rb-lb-1)*pre[j][j]+pre[j][(r-1)%j+1]+suf[j][(l-1)%j+1])%mod;
}
}
ans = ans % mod + mod;
ans = (ans >= mod) ? ans - mod : ans;
printf("%d",ans); puts("");
}
} return 0;
}

Code

从 洛谷P5309 Ynoi2011 初始化 看卡常的更多相关文章

  1. 洛谷P5309 Ynoi 2011 初始化 题解

    题面. 我也想过根号分治,但是题目刷得少,数组不敢开,所以还是看题解做的. 这道题目要用到根号分治的思想,可以看看这道题目和我的题解. 题目要求处理一个数组a,支持如下操作. 对一个整数x,对数组长度 ...

  2. 洛谷 P1186 【玛丽卡】

    这道题题目真的想吐槽一下...是在机房同学的解释下才看懂的.就是让你求在可以删一条边的情况下,并且删后保证可以到达终点时,求删了后的最大的最短路径. 70分暴力思路: 枚举删边,然后跑一下最短路即可, ...

  3. 洛谷 P1641 [SCOI2010]生成字符串

    洛谷 这题一看就是卡塔兰数. 因为\(cnt[1] \leq cnt[0]\),很显然的卡塔兰嘛! 平时我们推导卡塔兰是用一个边长为n的正方形推的, 相当于从(0,0)点走到(n,n)点,向上走的步数 ...

  4. 不失一般性和快捷性地判定决策单调(洛谷P1912 [NOI2009]诗人小G)(动态规划,决策单调性,单调队列)

    洛谷题目传送门 闲话 看完洛谷larryzhong巨佬的题解,蒟蒻一脸懵逼 如果哪年NOI(放心我这样的蒟蒻是去不了的)又来个决策单调性优化DP,那蒟蒻是不是会看都看不出来直接爆\(0\)?! 还是要 ...

  5. 【洛谷3674】小清新人渣的本愿(莫队,bitset)

    [洛谷3674]小清新人渣的本愿(莫队,bitset) 题面 洛谷,自己去看去,太长了 题解 很显然的莫队. 但是怎么查询那几个询问. 对于询问乘积,显然可以暴力枚举因数(反正加起来也是\(O(n\s ...

  6. BZOJ1060或洛谷1131 [ZJOI2007]时态同步

    BZOJ原题链接 洛谷原题链接 看上去就觉得是一道树形\(\mathtt{DP}\),不过到头来我发现我写了一个贪心.. 显然对越靠近根(记为\(r\))的边进行加权贡献越大,且同步的时间显然是从根到 ...

  7. 【流水调度问题】【邻项交换对比】【Johnson法则】洛谷P1080国王游戏/P1248加工生产调度/P2123皇后游戏/P1541爬山

    前提说明,因为我比较菜,关于理论性的证明大部分是搬来其他大佬的,相应地方有注明. 我自己写的部分换颜色来便于区分. 邻项交换对比是求一定条件下的最优排序的思想(个人理解).这部分最近做了一些题,就一起 ...

  8. 洛谷 P6295 - 有标号 DAG 计数(生成函数+容斥+NTT)

    洛谷题面传送门 看到图计数的题就条件反射地认为是不可做题并点开了题解--实际上这题以我现在的水平还是有可能能独立解决的( 首先连通这个条件有点棘手,我们尝试把它去掉.考虑这题的套路,我们设 \(f_n ...

  9. 快速排序--洛谷卡TLE后最终我还是选择了三向切割

    写在前边 这篇文章呢,我们接着聊一下排序算法,我们之前已经谈到了简单插入排序 和ta的优化版希尔排序,这节我们要接触一个更"高级"的算法了--快速排序. 在做洛谷的时候,遇到了一道 ...

随机推荐

  1. 记一次血淋淋的MySQL崩溃修复案例

    摘要:今天给大家带来一篇MySQL数据库崩溃的修复案例 本文分享自华为云社区<记一次MySQL崩溃修复案例,再也不用删库跑路了>,作者: 冰 河. 问题描述 研究MySQL源代码,调试并压 ...

  2. spring boot 分布式session实现

    spring boot 分布式session实现 主要是通过包装HttpServletRequest将session相关的方法进行代理. 具体是的实现就是通过SessionRepositoryFilt ...

  3. 【HTML】学习路径1-网页基本结构-标签基本语法

    本系列将学习最基础的web前端知识: HTML---CSS---JavaScripts---jQuery 四大部分学习完以后再进入到JavaWeb的知识.(后端) 然后再学习SpringBoot技术. ...

  4. Filter(过滤器)、ThreadLocal(本地线程)、Listener(监听器)

    Filter(过滤器) Filter过滤器它的作用是:拦截请求,过滤响应. 过滤器链 1)执行的顺序依次是: A B C Demo03 C2 B2 A2 2)如果采取的是注解的方式进行配置,那么过滤器 ...

  5. 7个自定义定时任务并发送消息至邮箱或企业微信案例(crontab和at)

    前言 更好熟悉掌握at.crontab定时自定义任务用法. 实验at.crontab定时自定义任务运用场景案例. 作业.笔记需要. 定时计划任务相关命令及配置文件简要说明 at 工具 由包 at 提供 ...

  6. django 通过MQTT连接阿里云

    Django MQTT 连接阿里云 目录 Django MQTT 连接阿里云 目录 一.安装库 1.安装Python对接mqtt协议库,paho-mqtt 二. 设备认证,一机一密型接入 三.问题 1 ...

  7. Android、iOS平台RTMP/RTSP播放器实时音量调节

    介绍移动端RTMP.RTSP播放器实时音量调节之前,我们之前也写过,为什么windows播放端加这样的接口,windows端播放器在多窗口大屏显示的场景下尤其需要,尽管我们老早就有了实时静音接口,相对 ...

  8. KingbaseESV8R6 snapshot too old的配置和测试

    背景 书接上文,我们很好的理解了xmin和xid的区别.我们继续上文<KingbaseESV8R6不同隔离级下xmin的区别>来讨论 snapshot too old 的功能. 当king ...

  9. (数据科学学习手札141)利用Learn Git Branching轻松学习git常用操作

    1 简介 大家好我是费老师,Git作为世界上最流行的版本控制系统,可以说是每一位与程序打交道的朋友最值得学习的软件之一.除了管理自己的项目,如果你对参与开源项目感兴趣,那么Git更是联结Github. ...

  10. 通用 HTTP 签名组件的另类实现

    1.初衷 开发中经常需要做一些接口的签名生成和校验工作,最开始的时候都是每个接口去按照约定单独实现,久而久之就变的非常难维护,因此就琢磨怎么能够写了一个比较通用的签名生成工具. 2.思路 采用链式调用 ...