18.8.28 考试吐槽
我这篇博客真的就是用来吐槽赞美今天blutrex学长出的题啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊
为什么这么难?????? 然后就华丽的被林荫街的dalao们吊打教育人生了qwqwqwqwqwq
他们真的好强强强强qwqqqqqqqqqqqqqqqqqqqqqqq
然后flx大佬 就是那个b 对就是他高一集训队 直接完美AK
我觉得我可以滚粗了qwqwqwqwqwqwqwqwqwqwqwqwq 16分真的可以说是历史新低了
还是说一下今天的题嘛QAQ
请允许我直接复制题解
然后看上去是非常简单的样子 实际上这道题细节真的血妈多qwqwqwqwq
因为我们要判断一个串是否合法 就要这样子
判断后一个字符的前端是否小于等于前一个字符的末端 如果是 那就不可能合法
那么就可以通过维护每个位置到他前面和后面第一个出现的某个字符的位置 比如右端点维护0的末端
左端点维护1的前端 就差不多这样时间复杂度就是n +n / 2 + n / 3 + n / 4 + ....大概是nlnn复杂度
代码
#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 5; int n,T,C,las[4],fr[4],bc[4],S,a[N],ans[4]; struct position { int ppos[4],fpos[4]; }s[N]; void init( ) { memset(las,0,sizeof(las)); for(int i = 1;i <= S;i ++) { if(a[i] != -1) las[a[i]] = i; for(int j = 0;j < C;j ++) s[i].ppos[j] = las[j]; } for(int i = 0;i < 4;i ++) las[i] = S + 1; for(int i = S;i >= 1;i --) { if(a[i] != -1) las[a[i]] = i; for(int j = 0;j < C;j ++) s[i].fpos[j] = las[j]; } } void solve( ) { for(int len = C;len < N + C;len ++) { for(int i = 0;i < C;i ++) fr[i] = len; memset(bc,0,sizeof(bc)); int st = 1; while(st <= S) { int side = min(S,st + len - 1); for(int i = 0;i < C;i ++) { if(s[st].fpos[i] <= side) fr[i] = min(s[st].fpos[i] - st,fr[i]);//相当于小字符串起始位置是0 if(s[side].ppos[i] >= i) bc[i] = max(s[side].ppos[i] - st + 1,bc[i]);//这里多加1 表示下个区间的左端点 } st = side + 1; } bool tag = false; for(int c = 0;c < C;c ++) { if(bc[c] == 0)// 还未出现过 fr[c] = c ? bc[c - 1] : 0,bc[c] = fr[c] + 1; else if(fr[c] > (c ? bc[c - 1] : 0)) fr[c] = c ? bc[c - 1] : 0; else if(c && fr[c] < bc[c - 1]) //严格< 因为右端点多了一 tag = true; } if(tag) continue; if (bc[C - 1] > len) continue; bc[C - 1] = len; int c; for (c = 0;c < C - 1 && ans[c] == bc[c] - fr[c];c ++);//可以直接做差 if (c < C - 1 && ans[c] > bc[c] - fr[c]) for (c = 0;c < C;c ++) ans[c] = bc[c] - fr[c]; } } int main( ) { freopen("char.in","r",stdin); freopen("char.out","w",stdout); scanf("%d%d",& T,& C); while(T --) { memset(a,-1,sizeof(a)); S = 0; scanf("%d",& n); for(int i = 1;i <= n;i ++) { int p,ss; scanf("%d%d",& p,& ss); a[p] = ss; S = max(S,p); } for(int i = 0;i < C;i ++) ans[i] = S + C; init( ); solve( ); if(ans[0] == S + C) printf("NO\n"); else { for(int i = 0;i < C - 1;i ++) printf("%d ",ans[i]); printf("%d\n",ans[C - 1]); } } }
第二题其实是一道经典的区间dp
就不说了...
第三题是一道最短路 然后拆点建图的方法很神奇 就用dijstra就差不多了
第三题我就不写了(逃
然后今天是非常颓废的一天(生无可恋.jpg
然后我还要说wans_是傻逼傻逼!!!!!!!!!!!!!!!!!!!!!
wans_驴骑萱是个威猛先生生霸王王洗发水水洁厕厕灵sbsbsbsbsbsbsbsbsbsbbsbsbsbsbs!!!!!!!!!!!!!!!!!!!