Preface

这场CF真是细节多的爆炸,B,C,F都是大细节题,每道题都写了好久的说

CSP前的打的最后一场比赛了吧,瞬间凉意满满

希望CSP可以狗住冬令营啊(再狗不住真没了)


A. Ivan the Fool and the Probability Theory

原谅我脑子不如陈指导好想不出来正解,然后打了个暴力3min找到规律做掉了。。。

然后讲一下正确的做法(陈指导教我的):

考虑我们用DP做出\(1\times m\)的矩阵的答案记为\(f_m\),考虑用它填了第一行

然后我们考虑第一行的填法:

  1. 第一行填的是\(0/1\)相间的,此时方案数有\(2\)种,考虑第二行填的就要么与第一行相同,要么与第一行相反。而且相同的不能连续填两行。我们仔细想想发现这个问题是不是和原来的一样了?(第一行看作某种状态,相反看作另一种状态),那么显然此时的方案数就是\(f_n\)
  2. 第一行填的是非\(0/1\)相间的,此时方案数有\(f_m-2\)种,显然第二行的填法只有每个与第一行的相反。而且这样的情况要一直延续到第\(n\)行,那么此时的总方案数就是\(f_m-2\)

综上所述,最后的答案就是\(f_n+f_m-2\)

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005,mod=1e9+7;
int n,m,f[N][2];
inline int sum(CI x,CI y)
{
int t=x+y; return t>=mod?t-mod:t;
}
int main()
{
scanf("%d%d",&n,&m); int lim=max(n,m); RI i;
for (f[1][0]=f[1][1]=1,f[2][0]=f[2][1]=2,i=3;i<=lim;++i)
f[i][0]=f[i-1][1],f[i][1]=sum(f[i-1][0],f[i-1][1]);
return printf("%d",sum(sum(sum(f[n][0],f[n][1]),sum(f[m][0],f[m][1])),mod-2)),0;
}

B. The World Is Just a Programming Task (Hard Version)

真NM烦人(假装有很多细节)的题,中间想了好多假算法的说

考虑我们先判掉必然无解的情况,那么显然这时我们可以搞出一个合法的括号序列

从这个合法的序列开始,我们把它的括号匹配求出来,同时记一个\(ct_i\)表示第\(i\)对括号里面有多少对匹配的括号

我们现在可以进行的交换有哪几类:

  1. 什么都不干(原地交换),此时的答案就是\(ct_0\)
  2. 交换某对匹配的括号,而这对括号外面没有其它的括号。我们可以发现此时这个串大概是\(\cdots(ct_i)\cdots\)的样子,因此我们交换后就变成\((\cdots)ct_i\)的样子,显然答案是了\(ct_i+1\)
  3. 交换某对匹配的括号,而这对括号外面只有一对其它的括号。此时的形式就是\(\cdots(\cdots(ct_i)\cdots)\cdots\),那么交换后就变成\(\cdots(\cdots)ct_i(\cdots)\cdots\)的样子,那么这时候答案就是\(ct_i+ct_0+1\)
  4. 交换某对匹配的括号,而这对括号外面有多于一对其它的括号。简单分析后答案不会改变
  5. 交换不匹配的括号,就是个弟弟玩意,显然答案也不会增加

那么这题总算是做完了

#include<cstdio>
#include<queue>
#define RI register int
#define CI const int&
using namespace std;
const int N=600005;
int n,dlt,st,cl,cr,stk[N],top,tot,L[N],R[N],ct[N],out[N],a[N],b[N],pfx[N],ans,x,y; char s[N];
struct heap
{
priority_queue <int,vector <int>,greater <int> > val,del;
inline void insert(CI x)
{
val.push(x);
}
inline void remove(CI x)
{
del.push(x);
}
inline int top(void)
{
while (!val.empty()&&!del.empty()&&val.top()==del.top())
val.pop(),del.pop(); return val.top();
}
}hp;
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
RI i,j; for (scanf("%d%s",&n,s+1),i=n+1;i<=(n<<1);++i)
a[i]=a[i-n]=s[i-n]=='('?1:-1,s[i-n]=='('?++cl:++cr;
if (cl!=cr) return puts("0\n1 1"),0;
for (i=1;i<=n;++i) hp.insert(pfx[i]=pfx[i-1]+a[i]);
for (i=1;i<=n;++i)
{
if (hp.top()+dlt>=0) { st=i; break; }
hp.remove(pfx[i]); dlt-=a[i]; hp.insert(0-dlt);
}
for (i=st;i<=st+n-1;++i) b[i-st+1]=a[i];
for (i=1;i<=n;++i) if (b[i]==1) stk[++top]=++tot,L[tot]=i;
else out[stk[top]]=stk[top-1],R[stk[top]]=i,++ct[stk[--top]];
for (ans=ct[0],x=y=i=1;i<=tot;++i)
{
if (!out[i]) { if (ct[i]+1>ans) ans=ct[i]+1,x=L[i],y=R[i]; }
else if (!out[out[i]]) { if (ct[i]+ct[0]+1>ans) ans=ct[i]+ct[0]+1,x=L[i],y=R[i]; }
}
return printf("%d\n%d %d",ans,(x+st-2)%n+1,(y+st-2)%n+1),0;
}

C. Queue in the Train

真是令人头晕脑涨的模拟题,我们直接按题意模拟操作

考虑我们用一些数据结构来维护答案:

  1. 给原数组按时间第一关键字,序号第二关键字排序,然后把可选每个数进行操作
  2. 开一个队列表示正在排队的人
  3. 有些人可能已经可以打水了,但是由于前面有人再它前面排队,因此它不会去打水。那么我们需要一个来维护这些人的编号
  4. 怎么判掉堆顶能不能去打水呢,我们再开一个set用来动态维护队列里正在排队的人的编号,每次用堆顶和set里的最小值比较即可

注意这些操作维护的顺序以及各种各样的细节

#include<cstdio>
#include<algorithm>
#include<queue>
#include<set>
#define RI register int
#define CI const int&
#define int long long
using namespace std;
const int N=100005;
struct data
{
int val,id;
friend inline bool operator < (const data& A,const data& B)
{
return A.val<B.val||(A.val==B.val&&A.id<B.id);
};
}a[N],t[N]; int n,p,ans[N],cnt; queue <int> q;
set <int> s; priority_queue <int, vector <int>, greater <int> > hp;
signed main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
RI i,j,pos; for (scanf("%I64d%I64d",&n,&p),i=1;i<=n;++i)
scanf("%I64d",&a[i].val),a[i].id=i; sort(a+1,a+n+1);
int cur=0; for (i=pos=1;i<=n;++i)
{
if (hp.empty()&&q.empty()&&pos<=n)
q.push(a[pos].id),s.insert(a[pos].id),cur=a[pos].val,++pos;
while (!hp.empty()) if (s.empty()||hp.top()<*s.begin())
q.push(hp.top()),s.insert(hp.top()),hp.pop(); else break; cur+=p;
while (pos<=n&&a[pos].val<=cur) t[++cnt]=a[pos++];
for (j=1;j<=cnt;++j) if (s.empty()||t[j].id<*s.begin())
q.push(t[j].id),s.insert(t[j].id); else hp.push(t[j].id);
ans[q.front()]=cur; s.erase(q.front()); q.pop(); cnt=0;
}
for (i=1;i<=n;++i) printf("%I64d ",ans[i]); return 0;
}

D. Catowice City

比B,C都清新的思维题,还算是帮CSP复习了一波板子

考虑由于每对人和猫都要作出选择,那么如果我们有人\(i\)和猫\(j\)的边,那么说明选了人\(i\)就必须选人\(j\)(除去与自己猫的边)

那么我们可以把这种关系看成一条有向边,那么容易发现SCC里的点都是互相依赖的,选了一个其它的都要选

那么我们先Tarjan缩点,然后如果最后的图就是一个联通块,那么显然是无解的

否则我们考虑找出一个度数为\(0\)的联通块,把这个联通块里的点选作人,其它的点都选做猫即可

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=1000005;
struct edge
{
int to,nxt;
}e[N]; int t,head[N],n,m,cnt,x,y,ans1[N],c1,ans2[N],c2;
int dfn[N],low[N],idx,col[N],stk[N],top,deg[N],scc; bool vis[N];
inline void clear(void)
{
RI i; for (i=1;i<=n;++i) head[i]=dfn[i]=low[i]=deg[i]=0;
cnt=scc=top=c1=c2=0;
}
inline void addedge(CI x,CI y)
{
e[++cnt]=(edge){y,head[x]}; head[x]=cnt;
}
#define to e[i].to
inline void Tarjan(CI now)
{
dfn[now]=low[now]=++idx; vis[stk[++top]=now]=1;
for (RI i=head[now];i;i=e[i].nxt)
if (!dfn[to]) Tarjan(to),low[now]=min(low[now],low[to]);
else if (vis[to]) low[now]=min(low[now],dfn[to]);
if (dfn[now]==low[now])
{
for (col[now]=++scc,vis[now]=0;stk[top]!=now;--top)
col[stk[top]]=scc,vis[stk[top]]=0; --top;
}
}
int main()
{
for (scanf("%d",&t);t;--t)
{
RI i,j; for (scanf("%d%d",&n,&m),i=1;i<=m;++i)
scanf("%d%d",&x,&y),x!=y&&(addedge(x,y),0);
for (i=1;i<=n;++i) if (!dfn[i]) Tarjan(i);
if (scc==1) { puts("No"); clear(); continue; }
for (j=1;j<=n;++j) for (i=head[j];i;i=e[i].nxt)
if (col[j]!=col[to]) ++deg[col[j]];
int id; for (i=1;i<=scc;++i) if (!deg[i]) { id=i; break; }
for (i=1;i<=n;++i) if (col[i]==id) ans1[++c1]=i; else ans2[++c2]=i;
puts("Yes"); printf("%d %d\n",c1,c2);
for (i=1;i<=c1;++i) printf("%d%c",ans1[i]," \n"[i==c1]);
for (i=1;i<=c2;++i) printf("%d%c",ans2[i]," \n"[i==c2]); clear();
}
return 0;
}

E. Turtle

思维难度较大的一道题,写到一半瞄了一眼陈指导的题解才会做

首先我们容易发现第一行的数必须是不降排序的,而第二行的数也要是不升的,证明非常简单,这里不再赘述

我们接下来考虑最大的路径是怎么走的,我们发现我们可以根据路径向下走的位置给它分类,例如我们设\(f(x)=\sum_{i=1}^n a_{1,i}=\sum_{i=p}^n a_{2,i}\)

那么我们考虑一个结论,当\(f(x)\)取\(\max\)时\(x=1\)或\(x=n\),证明如下:

当\(x\not = 1\)且\(x\not =n\)时,设\(f(x)\)为\(\max\)

\(f(x)=f(x-1)+a_{1,x}-a_{2,x-1}\)且\(f(x)\ge f(x-1)\)得出\(a_{1,x}-a_{2,x-1}\ge 0\)

同理对于\(f(x)\)与\(f(x+1)\)也有同样的分析,那么\(-a_{1,x+1}+a_{2,x}\ge 0\)

将不等式两边相加,得到\((a_{1,x}-a_{1,x+1})+(a_{2,x}-a_{2,x-1})\ge 0\),这显然与\(a_1\)不降与\(a_2\)不升矛盾,因此原命题得证

因此我们只需要让\(f(1)\)与\(f(n)\)尽量小即可,贪心地想把两个都要经过的起点终点选上最小值和次小值,考虑剩下的怎么填

由于总和确定,那么我们只要尽量使剩下数的分成两组,和最接近即可

考虑用DP算出答案,我们设\(f_{i,j,k}\)表示前\(i\)个数选了\(j\)个和为\(k\)能否达成,然后用bitset可以优化掉一维

那么知道答案怎么构造方案呢,发现数据中\(n\)非常小,因此我们可以用meet in middle构造一组解,状态的话状压一下就可以存了

#include<cstdio>
#include<bitset>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
typedef long long LL;
const int N=27,S=50005;
int n,a[N<<1],ans[2][N],ret,cur=1e9;
long long g[N][N*S]; bitset <N*S> f[N]; bool vis[N<<1];
inline bool cd(CI x,CI y)
{
return x>y;
}
inline void DFS1(CI nw,CI lim,CI cs=0,CI sum=0,const LL& sts=0)
{
if (nw>lim) return (void)(g[cs][sum]=sts);
DFS1(nw+1,lim,cs,sum,sts); DFS1(nw+1,lim,cs+1,sum+a[nw],sts|(1LL<<nw));
}
inline void DFS2(CI nw,CI lim,CI cs=0,CI sum=0,const LL& sts=0)
{
if (nw>lim)
{
if (cur-sum>=0&&~g[n-1-cs][cur-sum])
{
RI i,c=1; for (i=3;i<=(n<<1);++i)
if ((g[n-1-cs][cur-sum]>>i)&1LL) ans[0][++c]=a[i],vis[i]=1;
for (i=3;i<=(n<<1);++i)
if ((sts>>i)&1LL) ans[0][++c]=a[i],vis[i]=1;
for (c=0,i=3;i<=(n<<1);++i) if (!vis[i]) ans[1][++c]=a[i];
sort(ans[0]+1,ans[0]+n+1); sort(ans[1]+1,ans[1]+n+1,cd);
for (i=1;i<=n;++i) printf("%d%c",ans[0][i]," \n"[i==n]);
for (i=1;i<=n;++i) printf("%d%c",ans[1][i]," \n"[i==n]);
exit(0);
}
return;
}
DFS2(nw+1,lim,cs,sum,sts); DFS2(nw+1,lim,cs+1,sum+a[nw],sts|(1LL<<nw));
}
int main()
{
RI i,j; for (scanf("%d",&n),i=1;i<=n;++i) scanf("%d",&a[i]);
for (i=n+1;i<=(n<<1);++i) scanf("%d",&a[i]);
sort(a+1,a+(n<<1)+1); ans[0][1]=a[1]; ans[1][n]=a[2];
for (f[0][0]=1,i=3;i<=(n<<1);++i)
for (ret+=a[i],j=min(n-1,i-2);j;--j) f[j]|=(f[j-1]<<a[i]);
for (i=0;i<=ret;++i) if (f[n-1][i])
if (max(i,ret-i)<cur) cur=max(i,ret-i);
return memset(g,-1,sizeof(g)),DFS1(3,n+1),DFS2(n+2,n<<1),0;
}

F. Swiper, no swiping!

细节超级多的分类讨论题,写了一天最后偷来了错掉的数据才过掉

考虑把点按\(\mod 3\)的余数分为三类,记为\(Z,A,B\)

  • 如果有\(Z\)类的点,显然我们只用保留一个就可以了(SP:除了只有一个点的情况)
  • 如果\(A\)类的点之间有边相连,那么显然只用保留一对这样的点就可以了(SP:除了只有两个点相连的情况)
  • 如果B类点之间有环,那么我们可以搜出一个最短的环保留即可(SP:除了整张图就是一个大环的情况)
  • 如果存在两个即以上的\(A\)类点,那么我们显然可以找出一条连接两个\(A\)类点的边,满足这两点之间只有\(B\)类点(SP:除了整张图是一条链的情况)
  • 除去上面的情况那么现在我们的图一定只有一个\(A\)类点,然后剩下的\(B\)类点构成了森林。那么我们找出两个子树,从里面找出包含\(A\)的两个环即可(SP:除了整张图就是一个节点套上两个环的情况)

大体思路就是这样,关于一些原理的证明可以看官方题解:

然后就做完了,看了题解觉得很简单,写了代码就会很绝望……

#include<cstdio>
#include<vector>
#define RI register int
#define CI const int&
using namespace std;
const int N=500005;
struct edge
{
int to,nxt;
}e[N<<1]; int t,n,m,x[N],y[N],head[N],cnt,fa[N],deg[N],tim[N],cur,ans;
bool ext[N],flag; vector <int> v[N]; int q[N],pre[N],dep[N],vis[N];
inline void addedge(CI x,CI y)
{
e[++cnt]=(edge){y,head[x]}; head[x]=cnt;
e[++cnt]=(edge){x,head[y]}; head[y]=cnt;
}
inline void paint(CI s,CI t)
{
for (int nw=t;~nw;nw=pre[nw]) ext[nw]=1;
}
#define to e[i].to
inline void findcircle(CI now,CI tc)
{
if (flag) return; RI i; vis[now]=1; tim[now]=tc; int pos,cur=-1;
for (i=head[now];i;i=e[i].nxt)
if (vis[to]==1&&to!=pre[now]&&deg[to]%3==2)
if (dep[to]>cur) cur=dep[to],pos=to;
if (~cur)
{
for (int x=now;x!=pos;x=pre[x]) ext[x]=1;
flag=1; ext[pos]=1; return;
}
for (i=head[now];i;i=e[i].nxt) if (!vis[to]&&deg[now]%3==2)
pre[to]=now,dep[to]=dep[now]+1,findcircle(to,tc); vis[now]=2;
}
inline void BFS1(CI st)
{
RI H=0,T=1,i; for (i=1;i<=n;++i) pre[i]=0;
pre[q[T]=st]=-1; while (H<T)
{
int now=q[++H]; if (now!=st&&deg[now]%3==1) return paint(st,now);
for (i=head[now];i;i=e[i].nxt)
if (!pre[to]) pre[to]=now,q[++T]=to;
}
}
inline void BFS2(CI st)
{
RI H=0,T=1,i; for (i=1;i<=n;++i) pre[i]=0;
pre[q[T]=st]=-1; while (H<T)
{
int now=q[++H]; if (now!=st&&vis[now]) return paint(st,now);
for (i=head[now];i;i=e[i].nxt)
if (!pre[to]) pre[to]=now,q[++T]=to;
}
}
#undef to
inline void output(void)
{
RI i; for (puts("Yes"),ans=0,i=1;i<=n;++i) if (!ext[i]) ++ans;
for (printf("%d\n",ans),i=1;i<=n;++i)
if (!ext[i]) printf("%d ",i); putchar('\n');
}
inline void clear(void)
{
for (RI i=1;i<=n;++i) head[i]=deg[i]=ext[i]=vis[i]=dep[i]=0,v[i].clear(); cnt=cur=flag=0;
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i,j; for (scanf("%d%d",&n,&m),i=1;i<=m;++i)
scanf("%d%d",&x[i],&y[i]),++deg[x[i]],++deg[y[i]];
if (n==1) { puts("No"); continue; }
for (i=1;i<=n;++i) if (deg[i]%3==0)
{
ext[i]=flag=1; break;
}
if (flag) { output(); clear(); continue; }
if (n==2) { puts("No"); clear(); continue; }
for (i=1;i<=m;++i) if (deg[x[i]]%3==1&&deg[y[i]]%3==1)
{
ext[x[i]]=ext[y[i]]=flag=1; break;
}
if (flag) { output(); clear(); continue; }
int ct1,ct2=0; for (i=1;i<=n;++i) if (deg[i]==2) ++ct2;
if (ct2==n) { puts("No"); clear(); continue; }
for (i=1;i<=m;++i) if (deg[x[i]]%3==2&&deg[y[i]]%3==2) addedge(x[i],y[i]);
for (i=1;i<=n;++i) pre[i]=0; for (i=1;i<=n;++i)
if (deg[i]%3==2&&!vis[i]) findcircle(i,++cur);
if (flag) { output(); clear(); continue; }
for (ct1=ct2=0,i=1;i<=n;++i) ct1+=(deg[i]==1),ct2+=(deg[i]==2);
if (ct1==2&&ct2==n-2) { puts("No"); clear(); continue; }
for (ct1=0,i=1;i<=n;++i) if (deg[i]%3==1) ++ct1;
if (ct1>=2)
{
for (i=1;i<=m;++i) if (deg[x[i]]%3!=2||deg[y[i]]%3!=2) addedge(x[i],y[i]);
for (i=1;i<=n;++i) if (deg[i]%3==1) { ct1=i; break; }
BFS1(ct1); output(); clear(); continue;
}
for (i=1;i<=n;++i) if (deg[i]%3==1) { ct1=i; break; }
for (ct2=0,i=1;i<=n;++i) ct2+=(deg[i]%3==2);
if (deg[ct1]==4&&ct2==n-1) { puts("No"); clear(); continue; }
for (i=1;i<=n;++i) vis[i]=0;
for (i=1;i<=m;++i)
{
if (x[i]==ct1) v[tim[y[i]]].push_back(y[i]),vis[y[i]]=1;
if (y[i]==ct1) v[tim[x[i]]].push_back(x[i]),vis[x[i]]=1;
}
for (ct2=0,ext[ct1]=1,i=1;i<=cur;++i) if (v[i].size()>=2)
{
BFS2(v[i][0]); if (++ct2==2) break;
}
output(); clear();
}
return 0;
}

Postscript

不说什么了,各路神仙保我CSP RP++++RP

Codeforces Round #594 (Div. 1)的更多相关文章

  1. Codeforces Round #594 (Div. 2)

    传送门 C. Ivan the Fool and the Probability Theory 题意: 给出一个\(n*m\)的方格,现在要给方格中的元素黑白染色,要求任一颜色最多有一个颜色相同的格子 ...

  2. Codeforces Round #594 (Div. 1) D. Catowice City 图论

    D. Catowice City In the Catowice city next weekend the cat contest will be held. However, the jury m ...

  3. Codeforces Round #594 (Div. 1) C. Queue in the Train 模拟

    C. Queue in the Train There are

  4. Codeforces Round #594 (Div. 1) D2. The World Is Just a Programming Task (Hard Version) 括号序列 思维

    D2. The World Is Just a Programming Task (Hard Version) This is a harder version of the problem. In ...

  5. Codeforces Round #594 (Div. 2) B. Grow The Tree 水题

    B. Grow The Tree Gardener Alexey teaches competitive programming to high school students. To congrat ...

  6. Codeforces Round #594 (Div. 2) A. Integer Points 水题

    A. Integer Points DLS and JLS are bored with a Math lesson. In order to entertain themselves, DLS to ...

  7. Codeforces Round #594 (Div. 1) A. Ivan the Fool and the Probability Theory 动态规划

    A. Ivan the Fool and the Probability Theory Recently Ivan the Fool decided to become smarter and stu ...

  8. B. Grow The Tree Codeforces Round #594 (Div. 2)

    Gardener Alexey teaches competitive programming to high school students. To congratulate Alexey on t ...

  9. Codeforces Round #594 (Div. 2)(A/B/C)

    A. Integer PointsDescription DLS and JLS are bored with a Math lesson. In order to entertain themsel ...

随机推荐

  1. JS 测试 Prototype

    JS 测试 Prototype 测试 JavaScript 框架库 - Prototype 引用 Prototype 如需测试 JavaScript 库,您需要在网页中引用它. 为了引用某个库,请使用 ...

  2. 通过程序调用微信公众号发消息api返回48001

    自己的订阅号,尝试通过写程序来给用户发消息.结果呢,接口返回报错:errcode=48001,errmsg = api unauthorized hint: [ZlPULa02942276!] 去微信 ...

  3. Oracle GoldenGate常用参数详解

    Oracle GoldenGate常用参数详解http://blog.itpub.net/28389881/viewspace-2564461/

  4. diango下载、创建、启动

    下载 命令行 pip install django==1.11.26 -i https://pypi.tuna.tsinghua.edu.cn/simple pycharm 创建项目 命令行 djan ...

  5. linux 启动jar包 指定yml配置文件和输入日志文件

    命令为: nohup java -jar project.jar  --spring.config.location=/home/project-conf/application.yml >  ...

  6. C语言 复习函数

    什么是函数呢? 首先函数是在完成特定任务的程序代码中,拥有自己独立的单元. 举个例子 “你可以拿本书吗?” ”你可以拿本语文书吗?“ “你可以拿苹果吗?”..... 如果要是放到程序里面估计要重复很多 ...

  7. Cocos2d-x游戏实例《忍者飞镖》之对象管理

    推荐移步至<忍者飞镖射幽灵>之对象管理阅读 配置环境:win7+Cocos2d-x.2.0.3+VS2012 目标读者:需了解游戏帧率以及回调函数的概念 一.引言 对具体游戏demo的分析 ...

  8. ABC135记录

    date: 2019-07-28 A - Harmony 题目大意: 给你两个不同的整数A和B,要求你找到一个整数K,同时满足|A-K|=|B-K|.找不到时,输出"IMPOSSIBLE&q ...

  9. 基于django的个人博客网站建立(七)

    基于django的个人博客网站建立(七) 前言 网站效果可点击这里访问 这次在原来的基础上添加或修改一些小功能 具体内容 1.代码高亮 在原来的blog-details.html页面添加下面的代码: ...

  10. SpringBoot2.0 整合 Shiro 框架,实现用户权限管理

    本文源码:GitHub·点这里 || GitEE·点这里 一.Shiro简介 1.基础概念 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理.作为一款安全 ...