【前言】
今天写题手感很好,写的都是1A,然而太蠢了做不动- -
开场自己切了三个水题,队友写了一个水题就开始搞不动了,后面就过了一个05。
字符串如此SB的东西都忘了,今天赶紧补回来了。
rk53,校3/9

另:

仅次于清北,巅峰了属于是

1001. Calculus

【题意】

给了一堆发散的函数,和非负整数系数,问加起来后整点值[1,+∞)[1,+\infin)[1,+∞)求和是否发散。

【思路】

判断系数是否都为0即可。

没看到非负整数,于是还判断了一堆。

【参考代码】

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a),i##ss=(b);i<=i##ss;i++)
#define dwn(i,a,b) for(int i=(a),i##ss=(b);i>=i##ss;i--)
#define deb(x) cerr<<(#x)<<":"<<(x)<<'\n'
#define pb push_back
#define fi first
#define se second
#define hvie '\n'
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
int yh(){int ret=0;bool f=0;char c=getchar();while(!isdigit(c)){if(c==EOF)return -1;if(c=='-')f=1;c=getchar();}while(isdigit(c))ret=(ret<<3)+(ret<<1)+(c^48),c=getchar();return f?-ret:ret;
}
const int maxn=3e5+5;
int n;
char s[maxn];
void read_num(int l,int r,bool &G1,bool &is0){int a[2]={0,0},cur=0;for(int i=l;i<=r;i++){// cout<<s[i];if(s[i]=='/'){cur++;}else{a[cur]=a[cur]*10+(s[i]-'0');}}// cout<<" : !"<<cur<<" "<<a[0]<<" "<<a[1]<<hvie;if(cur==1){is0=a[0]==0;G1=a[0]>=a[1];}else{is0=a[0]==0;G1=a[0]>=1;}
}
bool proc(int l,int r){string t="";int i;bool G,is0;// for(i=l;i<=r;i++) cout<<s[i];// puts    ("");for(i=r;i>=l;i--){if(!isdigit(s[i])){t=s[i]+t;}else{read_num(l,i,G,is0);break;}}// cout<<"t="<<t<<" "<<G<<" "<<is0<<hvie;// puts("------------");if(t==""||t=="/x"||t=="sinx"||t=="cosx"||t=="/cosx"||t=="/sinx"||t=="x"){return is0;}else if(t=="^x"){return !G;}return 0;
}
int main(){dwn(_,yh(),1){scanf("%s",s+1);n=strlen(s+1);int lst=0;bool bad=0;rep(i,1,n){if(s[i]=='+'){if(!proc(lst+1,i-1)){bad=1;break;}lst=i;}}if(!bad&&!proc(lst+1,n)) bad=1;puts(bad?"NO":"YES");}return 0;
}
/*
sin
cos
/sin
/cos
x
^x*/

1002. Kanade Loves Maze Designing

【题意】

一颗nnn个点,点有颜色的树,wu,vw_{u,v}wu,v​表示路径(u,v)(u,v)(u,v)上不同颜色点的个数,求所有的www然后进行一个奇怪的计算(就是乘上个可以预处理的系数)。

n≤2000n\leq 2000n≤2000

【思路】

每个点为根暴力DFS即可。

【参考代码】

#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
#define ri register int
using namespace std;typedef double db;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<int,ll> pil;
const int N=2005,mod1=1e9+7,mod2=1e9+9;int n,a[N][N],pw1[N],pw2[N];
int cnt[N],c[N];
vector<int>G[N];int add(int x,int y,int mod){return x+y>=mod?x+y-mod:x+y;}
int mul(int x,int y,int mod){return 1ll*x*y%mod;}
int qpow(int x,int y,int mod)
{int ret=1;for(;y;y>>=1,x=mul(x,x,mod)) if(y&1) ret=mul(ret,x,mod);return ret;
}int now,rt;
void dfs(int x,int fa)
{if(!cnt[c[x]]) ++now;++cnt[c[x]];a[rt][x]=now;for(auto v:G[x]){if(v==fa) continue;dfs(v,x);}--cnt[c[x]];if(!cnt[c[x]]) --now;
}int main()
{//freopen("ttt.in","r",stdin);//freopen("a.out","w",stdout);for(int i=0;i<N;++i) pw1[i]=qpow(19560929,i,mod1);for(int i=0;i<N;++i) pw2[i]=qpow(19560929,i,mod2);    int T;scanf("%d",&T);while(T--){scanf("%d",&n);for(int i=1;i<=n;++i) G[i].clear();for(int i=2,x;i<=n;++i){scanf("%d",&x);G[x].pb(i);G[i].pb(x);} for(int i=1;i<=n;++i) scanf("%d",&c[i]);for(int i=1;i<=n;++i) rt=i,now=0,dfs(i,0);for(int i=1;i<=n;++i) {int ans1=0,ans2=0;for(int j=1;j<=n;++j){ans1=add(ans1,mul(a[i][j],pw1[j-1],mod1),mod1);ans2=add(ans2,mul(a[i][j],pw2[j-1],mod2),mod2);}printf("%d %d\n",ans1,ans2);}}return 0;
}

1003. Cycle Binary

【题意】

一个01串可以表示为kp+p′kp+p'kp+p′的形式,其中ppp是最短的循环节长度,p′p'p′是循环节的前缀,kkk是重复次数。

求长度为nnn的所有01串的kkk的和。

【思路】
显然我不会数学。

【参考代码】

n≤109n\leq 10^9n≤109

#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
using namespace __gnu_pbds;
#define rep(i,a,b) for(int i=(a),i##ss=(b);i<=i##ss;i++)
#define dwn(i,a,b) for(int i=(a),i##ss=(b);i>=i##ss;i--)
#define deb(x) cerr<<(#x)<<":"<<(x)<<'\n'
#define pb push_back
#define fi first
#define se second
#define hvie '\n'
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
ll yh(){int ret=0;bool f=0;char c=getchar();while(!isdigit(c)){if(c==EOF)return -1;if(c=='-')f=1;c=getchar();}while(isdigit(c))ret=(ret<<3)+(ret<<1)+(c^48),c=getchar();return f?-ret:ret;
}
const int maxn=5e7+5,N=5e6,mod=998244353;
ll f[maxn],pw[maxn];
ll add(ll x,ll y){x+=y;return x>=mod?x-mod:x;}
ll sub(ll x,ll y){x-=y;return x< 0?x+mod:x;}
ll ksm(ll a,ll b,ll c=1){for(;b;b>>=1,a=a*a%mod) if(b&1) c=c*a%mod;return c;
}
gp_hash_table<ll,ll>h;
ll S(ll n){if(n<=N) return f[n];if(h[n]) return h[n];ll tmp=2;for(ll l=2,r;l<=n;l=r+1){r=n/(n/l);tmp=add(tmp,(r-l+1)%mod*S(n/l)%mod);}return h[n]=sub(ksm(2ll,n+1),tmp);
}
ll g[maxn];
int main(){// f[1]=1;pw[0]=1;f[0]=0;rep(i,1,N){pw[i]=pw[i-1]*2ll%mod;f[i]=add(f[i],pw[i]);for(int j=i+i;j<=N;j+=i) f[j]=sub(f[j],f[i]);}rep(i,1,N) g[i]=f[i],f[i]=add(f[i-1],f[i]);dwn(_,yh(),1){ll n=yh();ll ans=0;ll m=n/2;for(ll i=1;i<=m;i++){ans=add(ans,(n/i-1)*g[i]%mod);}cout<<add(ksm(2ll,n),ans)<<hvie;}return 0;
}

1004. Display Substring

【题意】

一个长度为nnn的字符串SSS,每个字符有一个权值wiw_iwi​,求所有本质不同的子串中,权值第KKK小的权值是多少。

n≤105,wi≤100n\leq 10^5,w_i\leq 100n≤105,wi​≤100

【思路】

首先一般求第KKK啥的都可以二分这个权值ccc,问题转化为求有多少个本质不同的子串权值小于等于ccc。然后给权值求一个前缀和可以很方便求出一段子串的权值。

考虑后缀自动机,自动机上每个点实际上已经代表了本质不同的子串,和它对应可能的长度区间,我们每次二分这个长度就可以求出有多少个可行的长度了。

复杂度是O(nlog⁡nlog⁡W)O(n\log n\log W)O(nlognlogW)

一个可以跑的更快的优化是,实际上每个节点对应的endpos是往上传递的,而我们二分长度时也是从某个endpos处二分可行的长度,那么我们只需要在parent树的叶子处二分就可以了,可能随机数据下能快不少,然后由于内外层二分移动方向是相同的,所以再记一个之前二分区间甚至可以更快。

事实上,据说由于这个特性可以把长度二分的这个log⁡n\log nlogn优化掉,但是我不会。

【参考代码】

#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
#define ri register int
using namespace std;typedef double db;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<int,ll> pil;
const int N=2e5+10,inf=0x3f3f3f3f;int n;
ll K;
int pos[N],sum[N],val[26];
char s[N];struct SAM
{ll tot;int goal;int sz,las,rt;int fa[N],mx[N],ch[N][26];void init(){for(int i=0;i<=sz;++i) {fa[i]=mx[i]=pos[i]=0;memset(ch[i],0,sizeof(ch[i]));}sz=las=rt=1;}void extend(int x,int i){int p,q,np,nq;p=las;las=np=++sz;mx[np]=mx[p]+1;pos[np]=i;for(;p && !ch[p][x];p=fa[p]) ch[p][x]=np;if(!p) fa[np]=1;else{q=ch[p][x];if(mx[q]==mx[p]+1) fa[np]=q;else{nq=++sz;mx[nq]=mx[p]+1;pos[nq]=i;memcpy(ch[nq],ch[q],sizeof(ch[q]));fa[nq]=fa[q];fa[q]=fa[np]=nq;for(;ch[p][x]==q;p=fa[p]) ch[p][x]=nq;}}}ll check(int k){goal=k;tot=0;for(int x=2;x<=sz;++x){if(!pos[x]) continue;int l=mx[fa[x]]+1,r=mx[x],res=mx[fa[x]];//printf("x:%d pos[x]:%d goal:%d [%d,%d]\n",x,pos[x],goal,l,r);while(l<=r){int mid=(l+r)>>1;if(sum[pos[x]]-sum[pos[x]-mid]<=goal) res=mid,l=mid+1;else r=mid-1;}//printf("res:%d add:%d\n",res,res-(mx[fa[x]]+1)+1);tot+=res-(mx[fa[x]]+1)+1;}//printf("%d!!!tot:%lld\n",k,tot);return tot;}
}S;int main()
{ //freopen("1004.in","r",stdin);//freopen("my.out","w",stdout);int T;scanf("%d",&T);while(T--){scanf("%d%lld%s",&n,&K,s+1);for(int i=0;i<26;++i) scanf("%d",&val[i]);for(int i=1;i<=n;++i)sum[i]=sum[i-1]+val[s[i]-'a'];S.init();for(int i=1;i<=n;++i) {S.extend(s[i]-'a',i);}int l=1,r=sum[n],ans=-1;while(l<=r){int mid=(l+r)>>1;if(S.check(mid)>=K) ans=mid,r=mid-1;else l=mid+1;}printf("%d\n",ans);}return 0;
}

1005. Didn’t I Say to Make My Abilities Average in the Next Life?!

【题意】

长度为nnn的序列,有mmm个询问,每次询问一个区间[l,r][l,r][l,r]所有子区间最大值与最小值的平均值的期望。

n,m≤2×105n,m\leq 2\times 10^5n,m≤2×105

【思路】

实际上我们要做的就是求每个区间的所有子区间的最大值和最小值的和。

这个东西是个原题HNOI2016的序列,这里就不说了。

大概可以用莫队、笛卡尔树、历史最值线段树等多种方法做。

【参考代码】

莫队O(nnlog⁡n)O(n\sqrt n\log n)O(nn​logn)

#include <bits/stdc++.h>
using namespace std;
#define int long longconst int maxn = 210010;
const int MOD = 1e9 + 7;int t, n, Q;
int belong[maxn];
struct Node {int l, r, id;bool friend operator < (const Node &a, const Node &b) {if (belong[a.l] == belong[b.l]) return a.r < b.r;return belong[a.l] < belong[b.l];}
} q[maxn];
int a[maxn];int ksm(int a, int b, int p) {int s = 1;for (; b; b >>= 1, a = a * a % p) if (b & 1) s = s * a % p;return s;
}namespace Mn {int loger[maxn], minn[maxn][30];
int minid[maxn][30];
int a[maxn];
inline void pre(int n) {loger[1] = 0;for (int i = 2; i <= n; ++i) {loger[i] = loger[i - 1];if ( i == (1 << loger[i] + 1)) ++ loger[i];}for (int i = n; i >= 1; --i) {minn[i][0] = a[i];minid[i][0] = i;for (int j = 1; i + (1 << j) - 1 <= n; ++j) {minn[i][j] = min(minn[i][j - 1], minn[i + (1 << j - 1)][j - 1]);if (minn[i][j] == minn[i][j - 1]) minid[i][j] = minid[i][j - 1];if (minn[i][j] == minn[i + (1 << j - 1)][j - 1]) minid[i][j] = minid[i + (1 << j - 1)][j - 1];}}
}
inline int queryMin(int l, int r) {int k = loger[r - l + 1];if (minn[l][k] < minn[r - (1 << k) + 1][k]) return minid[l][k];return minid[r - (1 << k) + 1][k];
}
int ansmn[maxn], flMn[maxn], frMn[maxn];
int sta[maxn], top;
inline void dpMn(int n, int *f) {sta[top = 1] = 0;for (int i = 1; i <= n; ++i) {while (a[sta[top]] > a[i]) -- top;f[i] = (i - sta[top]) * a[i] + f[sta[top]];sta[++top] = i;}
}
inline int upd_R(int l, int r) {int p = queryMin(l, r + 1);return ((p - l + 1) * a[p] % MOD + flMn[r + 1] - flMn[p]) % MOD;
}
inline int upd_L(int l, int r) {int p = queryMin(l - 1, r);return ((r - p + 1) * a[p] % MOD + frMn[l - 1] - frMn[p]) % MOD;
}
void Mn() {a[0] = -(1LL << 60);pre(n);dpMn(n, flMn);reverse(a + 1, a + n + 1);dpMn(n, frMn);reverse(a + 1, a + n + 1);reverse(frMn + 1, frMn + n + 1);a[0] = 0;int L = 1, R = 1, ans = a[1];for (int i = 1; i <= Q; ++i) {while (R < q[i].r) ans = (ans + upd_R(L, R++)) % MOD;while (R > q[i].r) ans = (ans - upd_R(L, --R)) % MOD;while (L > q[i].l) ans = (ans + upd_L(L--, R)) % MOD;while (L < q[i].l) ans = (ans - upd_L(++L, R)) % MOD;ans = (ans + MOD) % MOD;int l = (q[i].r - q[i].l + 1);ansmn[q[i].id] = ans * ksm(l * (l + 1) % MOD, MOD - 2, MOD) % MOD;}
}
}namespace Mx {int loger[maxn], maxx[maxn][30], a[maxn];
int maxid[maxn][30];
inline void pre(int n) {loger[1] = 0;for (int i = 2; i <= n; ++i) {loger[i] = loger[i - 1];if ( i == (1 << loger[i] + 1)) ++ loger[i];}for (int i = n; i >= 1; --i) {maxx[i][0] = a[i];maxid[i][0] = i;for (int j = 1; i + (1 << j) - 1 <= n; ++j) {maxx[i][j] = max(maxx[i][j - 1], maxx[i + (1 << j - 1)][j - 1]);if (maxx[i][j] == maxx[i][j - 1]) maxid[i][j] = maxid[i][j - 1];if (maxx[i][j] == maxx[i + (1 << j - 1)][j - 1]) maxid[i][j] = maxid[i + (1 << j - 1)][j - 1];}}
}
inline int queryMax(int l, int r) {int k = loger[r - l + 1];if (maxx[l][k] > maxx[r - (1 << k) + 1][k]) return maxid[l][k];return maxid[r - (1 << k) + 1][k];
}
int ansmx[maxn], flMx[maxn], frMx[maxn];
int sta[maxn], top;
inline void dpMx(int n, int *f) {sta[top = 1] = 0;for (int i = 1; i <= n; ++i) {while (a[sta[top]] < a[i]) -- top;f[i] = (i - sta[top]) * a[i] + f[sta[top]];sta[++top] = i;}
}
inline int upd_R(int l, int r) {int p = queryMax(l, r + 1);return ((p - l + 1) * a[p] % MOD + flMx[r + 1] - flMx[p]) % MOD;
}
inline int upd_L(int l, int r) {int p = queryMax(l - 1, r);return ((r - p + 1) * a[p] % MOD + frMx[l - 1] - frMx[p]) % MOD;
}
void Mx() {a[0] = 1LL << 60;pre(n);dpMx(n, flMx);reverse(a + 1, a + n + 1);dpMx(n, frMx);reverse(a + 1, a + n + 1);reverse(frMx + 1, frMx + n + 1);a[0] = 0;int L = 1, R = 1, ans = a[1];for (int i = 1; i <= Q; ++i) {while (R < q[i].r) ans = (ans + upd_R(L, R++)) % MOD;while (R > q[i].r) ans = (ans - upd_R(L, --R)) % MOD;while (L > q[i].l) ans = (ans + upd_L(L--, R)) % MOD;while (L < q[i].l) ans = (ans - upd_L(++L, R)) % MOD;ans = (ans + MOD) % MOD;int l = (q[i].r - q[i].l + 1);ansmx[q[i].id] = ans * ksm(l * (l + 1) % MOD, MOD - 2, MOD) % MOD;}
}
}void input() {cin >> n >> Q;for (int i = 1; i <= n; ++i) {cin >> a[i];Mx::a[i] = Mn::a[i] = a[i];}int block = n / sqrt(Q) + 1;for (int i = 1; i <= n; ++i) belong[i] = (i / block) + 1;for (int i = 1; i <= Q; ++i) {cin >> q[i].l >> q[i].r;q[i].id = i;}sort(q + 1, q + Q + 1);
}signed main() {ios_base::sync_with_stdio(false);cin.tie(NULL);int Case;cin >> Case;while (Case--) {input();Mn::Mn();Mx::Mx();for (int i = 1; i <= Q; ++i) {cout << (Mx::ansmx[i] + Mn::ansmn[i]) % MOD << endl;}}return 0;
}

1006. Directed Minimum Spanning Tree

【题意】

【思路】
显然我不会图论。

1007. Increasing Subsequence

【题意】

给定一个长度为nnn的排列aia_iai​,问有多少种极长上升子序列。(即不是任何一个其他上升子序列的子序列)

n≤105n\leq 10^5n≤105

【思路】

首先我们考虑怎么暴力,设fif_ifi​表示所有考虑到第iii位的上升子序列的个数,那么答案就是每个后面不存在比它大的数字的iii的fif_ifi​之和。而初值是所有左边不存在比它小的数字的fff为1。

转移呢?我们考虑一个子序列x<y<zx<y<zx<y<z,如果ax<ay<aza_x<a_y<a_zax​<ay​<az​,那么fxf_xfx​必然不可能转移到fzf_zfz​,因为中间有个aya_yay​,于是能转移的就很明显了:对于一个iii,我们将比aia_iai​小的iii前的数全部拿出来做单调栈(栈顶最小),所有剩下的数就是能转移到fif_ifi​的。

于是问题转化为了维护一个单调栈和单调栈内fff的和。

一种方法是考虑维护这样一个函数:find(l,r,mx)find(l,r,mx)find(l,r,mx),表示在[l,r][l,r][l,r],只用≥mx\geq mx≥mx的数字组成的单调栈的fff的和是多少,我们按照数字顺序从小到大考虑,这样每个位置的答案就是find(1,i,0)find(1,i,0)find(1,i,0)

这个东西是可以用线段树维护的,具体来说,线段树的每个位置维护它的右孩子的最大值rmxrmxrmx,左区间find(l,mid,rmx)find(l,mid,rmx)find(l,mid,rmx)的答案lanslanslans。这是维护线段树上每个节点的时候,那么怎么维护一个区间的这个函数呢?

我们考虑从右到左合并区间,现在右边已经合出来一个区间BBB(由线段树上某些节点合成),左边的区间是AAA(线段树上的一个节点)。设BBB中最大值为PmxPmxPmx,那么接下来有几种情况:

  • 若mx[A.rson]>Pmxmx[A.rson]>Pmxmx[A.rson]>Pmx,这说明右孩子对整个答案有贡献,而我们已经算出了lanslanslans,那么就可以只递归右孩子。
  • 若mx[A.rson]<Pmxmx[A.rson]<Pmxmx[A.rson]<Pmx,这说明右孩子对答案没贡献,我们递归左孩子就行。

这里这个lanslanslans的维护就是为了让线段树只递归一边,保证复杂度。

lanslanslans的维护在updateupdateupdate的时候调用findfindfind来维护即可。

复杂度O(nlog⁡2n)O(n\log ^2n)O(nlog2n)

还有一种方法是用分治来解决这个问题,比赛时我们写的也是这个,不过处理贡献没想明白,后面才想清楚。

当处理区间[l,r[l,r[l,r 时,令mmm 为[l,r][l,r][l,r] 的中点,对a[l,r]a[l,r]a[l,r]中所有元素按值依次从小到大处理。对[l,m][l,m][l,m]和[m+1,r][m+1,r][m+1,r]分别建单调栈。左边单调栈中的元素值从小到大,位置从大到小。右边的单调栈中元素值从小到大,位置从小到大。处理左边的元素时直接往单调栈里丢,处理右边的元素a[i]a[i]a[i]时通过单调栈找到[m+1,i−1][m+1,i-1][m+1,i−1] 中比他小的最靠右侧的元素a[j]a[j]a[j] 。然后在左侧的单调栈中找到比a[j]a[j]a[j]大的第一个元素和比a[i]a[i]a[i]小的最后一个元素。区间[l,m][l,m][l,m]对f[i]f[i]f[i]的贡献就来自单调栈里这两个元素之间的元素的fff 值之和。

复杂度同样是O(nlog⁡2n)O(n\log^2n)O(nlog2n)的,不过常数会小一点。

具体实现见代码。

【参考代码】

线段树

#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
#define ri register int
using namespace std;typedef double db;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<int,ll> pil;
const int N=1e5+10,inf=0x3f3f3f3f,mod=998244353;int n;
int a[N],b[N],f[N];void up(int &x,int y){x+=y;x%=mod;}struct Seg
{#define ls (x<<1)#define rs (x<<1|1)int Pmx;struct node{int sum,mx,lans;}t[N<<2];void build(int x,int l,int r){t[x].sum=0;t[x].mx=-1;t[x].lans=0;if(l==r) return;int mid=(l+r)>>1;build(ls,l,mid);build(rs,mid+1,r);}int query(int x,int l,int r,int L,int R)//find [L,R] use>P sum f{if(t[x].mx<Pmx) return 0;if(l==r){if(t[x].mx<Pmx) return 0;Pmx=max(Pmx,t[x].mx);return t[x].sum;}int mid=(l+r)>>1,ret=0;if(L<=l && r<=R){if(Pmx>t[rs].mx) return query(ls,l,mid,L,R);up(ret,query(rs,mid+1,r,L,R));Pmx=max(Pmx,t[x].mx);up(ret,t[x].lans);}else {if(R>mid) up(ret,query(rs,mid+1,r,L,R));if(L<=mid) up(ret,query(ls,l,mid,L,R));}return ret;}void update(int x,int l,int r,int p,int val){if(l==r) {t[x].mx=a[l];t[x].sum=val;return;}int mid=(l+r)>>1;if(p<=mid) update(ls,l,mid,p,val);else update(rs,mid+1,r,p,val);Pmx=t[rs].mx;t[x].lans=query(ls,l,mid,l,mid);t[x].sum=t[ls].sum+t[rs].sum;t[x].mx=max(t[ls].mx,t[rs].mx);}#undef ls#undef rs
}tr;int main()
{ int T;scanf("%d",&T);while(T--){scanf("%d",&n);for(int i=1,tmi=inf;i<=n;++i) {scanf("%d",&a[i]);b[a[i]]=i;if(tmi>a[i]) f[i]=1,tmi=a[i];else f[i]=0;}tr.build(1,1,n);for(int i=1;i<=n;++i){if(!f[b[i]]){tr.Pmx=0;f[b[i]]=tr.query(1,1,n,1,b[i]-1);}tr.update(1,1,n,b[i],f[b[i]]);}int ans=0;for(int i=n,tmx=0;i;--i){if(tmx<a[i]) up(ans,f[i]),tmx=a[i];}printf("%d\n",ans);}return 0;
}

分治

#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
#define ri register int
using namespace std;typedef double db;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<int,ll> pil;
const int N=1e5+10,inf=0x3f3f3f3f,mod=998244353;int n;
int a[N],f[N],sum[N];
int stl[N],str[N];
pii b[N];void up(int &x,int y){x+=y;x%=mod;}
int upm(int x){x%=mod;return x>=0?x:x+mod;}int find(int num,int l,int r)//find b[stl[pos]].fi>num
{int ret=r+1;while(l<=r){int mid=(l+r)>>1;if(a[stl[mid]]>=num) ret=mid,r=mid-1;else l=mid+1;}return ret;
}void divide(int l,int r)
{if(l==r) return;int mid=(l+r)>>1;divide(l,mid);//printf("now:%d %d\n",l,r);int lenl=0,lenr=0,cnt=0;for(int i=l;i<=r;++i) b[++cnt]=mkp(a[i],i);sort(b+1,b+cnt+1);for(int i=1;i<=cnt;++i){if(b[i].se<=mid){while(lenl && b[i].se>stl[lenl]) --lenl;stl[++lenl]=b[i].se;sum[lenl]=upm(sum[lenl-1]+f[b[i].se]);//printf("push:%d\n",b[i].fi);}else{while(lenr && b[i].se<str[lenr]) --lenr;str[++lenr]=b[i].se;//printf("nowstack:\n");//for(int i=1;i<=lenl;++i) printf("%d ",stl[i]);//puts("");int t=a[str[lenr-1]]+1;//printf("find:%d %d\n",t,b[i].fi);int lp=find(t,1,lenl),rp=find(b[i].fi,1,lenl)-1;//printf("lp:%d rp:%d\n",lp,rp);if(lp>rp) continue;up(f[b[i].se],upm(sum[rp]-sum[lp-1]));}}//for(int i=1;i<=n;++i) printf("%d ",f[i]);//puts("");divide(mid+1,r);
}int main()
{ int T;scanf("%d",&T);while(T--){scanf("%d",&n);for(int i=1,tmi=inf;i<=n;++i) {scanf("%d",&a[i]);if(tmi>a[i]) f[i]=1,tmi=a[i];else f[i]=0;}divide(1,n);int ans=0;for(int i=n,tmx=0;i;--i){if(tmx<a[i]) up(ans,f[i]),tmx=a[i];}printf("%d\n",ans);}return 0;
}

1008. Lawn of the Dead

【题意】

一个n×mn\times mn×m的网格图,从左上角出发走,每次只能往下或往右走,有其中kkk个格子不能走。问一共有多少格子可达。

n,m,k≤105n,m,k\leq 10^5n,m,k≤105

【思路】

我们每行能走到哪些格子可以由上一行转移过来。

我们可以考虑维护当前行有哪些格子可以走到。

按不能走的格子为分隔点,实际上就是要找到上一行在这个区间内能到达的最左的格子。

线段树维护即可,操作就是区间置0,区间置1和查询区间最左的1

复杂度O(klog⁡m)O(k\log m)O(klogm)

【参考代码】

#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
#define ri register int
using namespace std;typedef double db;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<int,ll> pil;
const int N=2e5+10,inf=0x3f3f3f3f;int n,m,k;
vector<int>G[N];struct Seg
{#define ls (x<<1)#define rs (x<<1|1)int lmost[N<<2],tag[N<<2];void pushup(int x){lmost[x]=min(lmost[ls],lmost[rs]);}void pushdown(int x,int l,int r){if(tag[x]!=-1){if(tag[x]){lmost[ls]=l;lmost[rs]=((l+r)>>1)+1;}else lmost[ls]=lmost[rs]=inf;tag[ls]=tag[x];tag[rs]=tag[x];tag[x]=-1;}}void build(int x,int l,int r){tag[x]=-1;lmost[x]=inf;if(l==r) {lmost[x]=(l==1?1:inf);return;}int mid=(l+r)>>1;build(ls,l,mid);build(rs,mid+1,r);pushup(x);}void update(int x,int l,int r,int L,int R,int op){if(L>R) return;if(L<=l && r<=R){tag[x]=op;if(op) lmost[x]=l;else lmost[x]=inf;return;}pushdown(x,l,r);int mid=(l+r)>>1;if(L<=mid) update(ls,l,mid,L,R,op);if(R>mid) update(rs,mid+1,r,L,R,op);pushup(x);}int find(int x,int l,int r,int L,int R){if(L>R) return inf;if(L<=l && r<=R) return lmost[x];int ret=inf,mid=(l+r)>>1;pushdown(x,l,r);if(L<=mid) ret=min(ret,find(ls,l,mid,L,R));if(R>mid) ret=min(ret,find(rs,mid+1,r,L,R));pushup(x);return ret;}#undef ls#undef rs
}tr;int main()
{ int T;scanf("%d",&T);while(T--){scanf("%d%d%d",&n,&m,&k);for(int i=1,x,y;i<=k;++i){scanf("%d%d",&x,&y);G[x].pb(y);}tr.build(1,1,m);ll ans=0;for(int i=1;i<=n;++i){G[i].pb(m+1);sort(G[i].begin(),G[i].end());int sz=G[i].size(),las=0;for(int j=0;j<sz;++j){int t=tr.find(1,1,m,las+1,G[i][j]-1);//printf("row:%d find:[%d,%d] %d\n",i,las+1,G[i][j]-1,t);if(t!=inf){ans+=G[i][j]-t;tr.update(1,1,m,G[i][j],G[i][j],0);tr.update(1,1,m,las+1,t-1,0);tr.update(1,1,m,t,G[i][j]-1,1);}else tr.update(1,1,m,las+1,G[i][j],0);las=G[i][j];}G[i].clear();}printf("%lld\n",ans);}return 0;
}

1009. License Plate Recognition

【题意】

给一个车牌,求每个文字的左右边界。

【思路】

可以垂直投影到一维区间,后六个为数字和字母,它们的区间是连续的,剩下的就是第一个汉字的了。

比赛时比较蠢写了个BFS。

【参考代码】

#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
#define ri register int
using namespace std;typedef double db;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<int,ll> pil;
const int N=2005,mod1=1e9+7,mod2=1e9+9;int n,m,cnt;
char a[35][105];
pii res[N];
queue<pii>q;
int dx[]={0,1,0,-1},dy[]={1,0,-1,0};int inmp(int x,int y)
{return 1<=x && x<=n && 1<=y && y<=m && a[x][y]=='#';
}pii bfs(int x,int y)
{while(!q.empty()) q.pop();q.push(mkp(x,y));a[x][y]='.';int mi=y,mx=y;while(!q.empty()){x=q.front().fi,y=q.front().se;q.pop();for(int i=0;i<4;++i){int nx=x+dx[i],ny=y+dy[i];if(!inmp(nx,ny)) continue;mi=min(ny,mi);mx=max(ny,mx);q.push(mkp(nx,ny));a[nx][ny]='.';}}return mkp(mi,mx);
}int main()
{ int T;scanf("%d",&T);n=30;m=100; for(int tt=1;tt<=T;++tt){cnt=0;for(int i=1;i<=n;++i) scanf("%s",a[i]+1);//for(int i=1;i<=n;++i) printf("%s\n",a[i]+1);for(int i=1;i<=n;++i){for(int j=1;j<=m;++j)if(a[i][j]=='#') res[++cnt]=bfs(i,j);}sort(res+1,res+cnt+1);// for(int i=1;i<=cnt;++i) printf("get:%d %d\n",res[i].fi,res[i].se);printf("Case #%d:\n",tt);int mi=m,mx=0;for(int i=1;i<=cnt-6;++i) mi=min(mi,res[i].fi),mx=max(mx,res[i].se);printf("%d %d\n",mi,mx);for(int i=cnt-5;i<=cnt;++i) printf("%d %d\n",res[i].fi,res[i].se);}return 0;
}

【多校训练】2021HDU多校4相关推荐

  1. HDU6578 2019HDU多校训练赛第一场 1001 (dp)

    HDU6578 2019HDU多校训练赛第一场 1001 (dp) 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6578 题意: 你有n个空需要去填,有 ...

  2. 2019牛客多校训练第十场F Popping Balloons

    2019牛客多校训练第十场F Popping Balloons 题意:二维平面内给你若干个点,然后你可以在x轴和y轴分别射三枪(每一枪的间隔是R),问最多能射掉多少气球. 题解:贪心.这个应该只能算作 ...

  3. 【2019杭电多校训练赛】HDU6681 / 1002-Rikka with Cake 题解(扫描线)

    [2019杭电多校训练赛]HDU6681 / 1002-Rikka with Cake 题解 题意 思路 代码 题目来自于:HDU6681 Rikka with Cake 题意 题目的大意是给定你一个 ...

  4. 选完校花又选校草,张朝阳为什么对造星如此执念?

    最近,有一场来自搜狐狐友的热门选秀吸引来了宁静.李斯羽.江映蓉.黄英等女明星评审,搜狐董事局主席兼首席执行官张朝阳也亲临坐镇,评审名单里还有柳岩.于莎莎.瞿颖.赵子琪等知名艺人-- 参赛者不是所谓的明 ...

  5. GPS北斗校时(NTP校时服务器)在某市国土资源局投入使用

    GPS北斗校时(NTP校时服务器)在某市国土资源局投入使用 GPS北斗校时(NTP校时服务器)在某市国土资源局投入使用 许多电脑网络都使用基于互联网的时间服务器以便保持自己系统的同步性.问题是,无论他 ...

  6. 小学教师计算机校本培训计划,校本培训工作计划

    南雁镇中心小学校本培训工作计划 为了进一步提高教师实施素质教育的能力与水平,全力打造一支师德修养高.业务素质精良.教学技能全面.教学基本功过硬.具有一定教科研能力.适应新时期新课程改革需求的教师队伍, ...

  7. 计算机培训校本研修心得,校本研修经验总结

    校本研修经验总结 课堂是教育教学研究的基地,标志着教学研究的重心要置于具体的课堂教学情境中.我们学校全体教师继续更新教育思想和教育观念,改革教学方法,各教研组面向学生均有序地组织了一系列教育教研活动: ...

  8. NTP校时器(NTP网络校时器-NTP校时系统)

    NTP校时器(NTP网络校时器-NTP校时系统) NTP校时器(NTP网络校时器-NTP校时系统) 技术交流-岳峰-15901092122:qq-522508213: 近几年来,随着变电站自动化水平的 ...

  9. 【多校训练】2021HDU多校6

    [前言] 这场比赛属实阴间,题十分诡异. 最后rk78,校3/9 1001. Yes Prime Minister [题目] 给定一个数 x x x,求一个最短的区间 [ l , r ] [l,r] ...

最新文章

  1. 从搞笑到高效,构建敏捷团队的基础原则
  2. Springboot-读取核心配置文件及自定义配置文件
  3. 引号不是字符串中唯一的可以被转义字符。下面是常见的转义序列列表:
  4. 全国计算机等级考试题库二级C操作题100套(第29套)
  5. html.parser python_python模块之HTMLParser
  6. 对于数据,科技小白提出了灵魂三问:从哪儿来?到哪儿去?能干什么?
  7. [转]Android web开发快速入门
  8. html 多页面合并,让多个HTML页面 使用 同一段HTML代码
  9. android菜单动画,利用 android studio 制作一个菜单动画
  10. 推荐系统-Task02数据库基本使用
  11. java遍历文件夹并复制文件到指定目录
  12. 进击的UI---------------- UITextFieldUIButton
  13. 【情感识别】基于matlab PNN概率神经网络语音情感识别【含Matlab源码 544期】
  14. coon.php连接,PHP 连接 MySQL
  15. 2D制作动画软件:Cartoon Animato 支持win/mac 中文激活版
  16. 微信上网卡WeSim悄然发布
  17. TextCNN——基于卷积神经网络的文本分类学习
  18. Toggle Buttons(一)
  19. 如何利用imagick合并2张图后为动态效果
  20. 彩色图片变成黑白打印风格图片的一种方式

热门文章

  1. 大数据进阶之路——Spark SQL 之 DataFrameDataset
  2. 计算机大龄女博士找工作只能去学校吗,34岁离异女博士,到底是励志还是心酸...
  3. r语言拟合MA模型,及时序图,自相关图,偏自相关图
  4. 陈欧口述:如何凭“四大质疑”将企业做上市
  5. 区块链投资需要多少钱
  6. 解决STM32新增加函数出现Undefined symbol HAL_ADC_Init (referred from main.o). 问题
  7. 安徽师范大学计算机学院教师,安徽师范大学数学计算机科学学院导师介绍:鲁世平...
  8. SE16N新改表内容方法
  9. 2020复工后刷脸支付将迎来高潮
  10. java.sql.SQLException: Subquery returns more than 1 row