A.找到最大值x,再找出最长的连续的x。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 6 typedef long long ll; 7 using namespace std; 8 9 const int N=100010; 10 int n,tot,mx,ans,a[N]; 11 12 int main(){ 13 scanf("%d",&n); 14 rep(i,1,n) scanf("%d",&a[i]),mx=max(mx,a[i]); 15 rep(i,1,n) if (a[i]==mx) tot++; else ans=max(ans,tot),tot=0; 16 printf("%d ",max(ans,tot)); 17 return 0; 18 }
B.连续k个最大值后跟1个次大值,如此循环。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 6 typedef long long ll; 7 using namespace std; 8 9 const int N=400010; 10 int n,m,k,a[N]; 11 12 int main(){ 13 scanf("%d%d%d",&n,&m,&k); 14 rep(i,1,n) scanf("%d",&a[i]); 15 sort(a+1,a+n+1); 16 int s=m/(k+1),p=m%(k+1); 17 cout<<1ll*s*(1ll*k*a[n]+a[n-1])+1ll*p*a[n]<<endl; 18 return 0; 19 }
C.二分答案,根据风向向量和与目标距离之间的曼哈顿距离判断是否可行。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 6 typedef long long ll; 7 using namespace std; 8 9 const int N=200010; 10 char op; 11 int n; 12 ll x1,y1,x2,y2; 13 struct P{ ll x,y; }p[N]; 14 15 int main(){ 16 cin>>x1>>y1>>x2>>y2>>n; x2-=x1; y2-=y1; 17 p[0]=(P){0,0}; 18 rep(i,1,n){ 19 scanf(" %c",&op); p[i]=p[i-1]; 20 if (op=='U') p[i].y++; 21 if (op=='D') p[i].y--; 22 if (op=='L') p[i].x--; 23 if (op=='R') p[i].x++; 24 } 25 ll L=1,R=1e15; 26 while (L<R){ 27 ll mid=(L+R)>>1,x=(mid/n)*p[n].x+p[mid%n].x,y=(mid/n)*p[n].y+p[mid%n].y; 28 if (abs(x2-x)+abs(y2-y)<=mid) R=mid; else L=mid+1; 29 } 30 if (L>1e14) puts("-1"); else cout<<L<<endl; 31 return 0; 32 }
D.f[n]=f[n-1]+f[n-m],矩阵快速幂优化。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 6 typedef long long ll; 7 using namespace std; 8 9 const int N=110,mod=1e9+7; 10 ll n; 11 int m; 12 13 struct Mat{ int a[N][N]; Mat(){memset(a,0,sizeof(a));} }ans; 14 15 Mat operator *(const Mat &a,const Mat &b){ 16 Mat c; 17 rep(i,1,m) rep(j,1,m) rep(k,1,m) c.a[i][k]=(c.a[i][k]+1ll*a.a[i][j]*b.a[j][k])%mod; 18 return c; 19 } 20 21 Mat ksm(ll n){ 22 Mat res,a; 23 rep(i,1,m) a.a[i+1][i]=1,res.a[i][i]=1; 24 a.a[1][m]=1; a.a[m][m]=1; 25 for (; n; a=a*a,n>>=1) 26 if (n & 1) res=res*a; 27 return res; 28 } 29 30 int main(){ 31 cin>>n>>m; 32 if (n<m){ puts("1"); return 0; } 33 rep(i,1,m-1) ans.a[1][i]=1; ans.a[1][m]=2; 34 ans=ans*ksm(n-m); 35 cout<<ans.a[1][m]<<endl; 36 return 0; 37 }
E.26*26*26>10000,确定置换后每个位置的26进制(即将x表示为a*26^2+b*26+c,三次询问分别确定a,b,c)。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 5 using namespace std; 6 7 const int N=10010; 8 int n; 9 char s[N],q[3][N],g[3][N],ans[N]; 10 11 int main(){ 12 scanf("%s",s); n=strlen(s); 13 rep(i,0,n-1){ 14 q[0][i]=(i/(26*26)%26+'a'); 15 q[1][i]=(i/26%26+'a'); 16 q[2][i]=(i%26+'a'); 17 } 18 rep(i,0,2) printf("? %s ",q[i]),fflush(stdout),scanf("%s",g[i]); 19 rep(i,0,n-1){ 20 int tmp=(g[0][i]-'a')*26*26+(g[1][i]-'a')*26+(g[2][i]-'a'); 21 ans[tmp]=s[i]; 22 } 23 printf("! %s",ans); 24 return 0; 25 }
F.一个自然的想法是,用二进制压位S表示留下某些字母后这个串是否合法,权值设为串长,然后从11..1开始BFS找到权值最小的点即可。
考虑如何判断一个S是否合法,一个暴力的想法是枚举i,j,然后O(n)判定是否存在某对i,j之间的所有字符都被删去。
但这样复杂度是$O(n2^pp^2)$的,考虑用i,j来筛S。
枚举i,j,考虑原串中每对i,j,如果S在i+1~j-1上的每种字符上都为0,那么这个S就是不合法的。
在考虑每对i,j时,这样的S是一个高维前缀。于是打标记,然后做一个高维后缀和就可以知道每个S在考虑i,j两种字母时是否合法了。
于是复杂度为枚举i,j并打标记的$O(np^2)$+对每个不合法i,j做高维后缀和的$O(2^pp^3)$+对每个S枚举i,j判断是否合法的$O(2^pp^2)$+从11..1开始BFS的$O(2^p)$,也就是$O(2^pp^3)$。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 using namespace std; 5 6 const int N=300010,K=18; 7 char s[N]; 8 bool sm[K*K][N],b[N],vis[N]; 9 int n,p,tot,ans,ss,w[K][K],mp[K][K],a[N],cnt[K],q[N]; 10 11 int cal(int S){ int res=0; rep(i,1,p) if (S&(1<<(i-1))) res+=cnt[i]; return res; } 12 13 void work(int x,int y,int k){ 14 int tot=0; 15 rep(i,1,n) if (s[i]-'a'+1==x || s[i]-'a'+1==y) a[++tot]=i; 16 rep(i,1,tot-1) if ((s[a[i]]-'a'+1==x && s[a[i+1]]-'a'+1==y) || (s[a[i]]-'a'+1==y && s[a[i+1]]-'a'+1==x)){ 17 int S=0; 18 rep(j,a[i]+1,a[i+1]-1) S|=1<<(s[j]-'a'); 19 S^=ss; sm[k][S]=1; 20 } 21 } 22 23 int main(){ 24 scanf("%d%d%s",&n,&p,s+1); ans=n+1; ss=(1<<p)-1; 25 rep(i,1,n) cnt[s[i]-'a'+1]++; 26 rep(i,1,p) rep(j,1,p) scanf("%d",&mp[i][j]); 27 rep(i,1,p) rep(j,i,p) if (!mp[i][j]) w[i][j]=++tot,work(i,j,tot); 28 rep(x,1,tot){ 29 for (int i=1; i<=ss; i<<=1) 30 rep(j,1,ss) if (j&i) sm[x][j^i]|=sm[x][j]; 31 } 32 rep(S,0,ss){ 33 b[S]=1; 34 rep(i,1,p) rep(j,i,p) 35 if (S&(1<<(i-1)) && S&(1<<(j-1)) && !mp[i][j] && sm[w[i][j]][S]){ b[S]=0; break; } 36 } 37 q[1]=ss; vis[ss]=1; 38 for (int st=0,ed=1; st!=ed; ){ 39 int S=q[++st]; ans=min(ans,cal(S)); 40 rep(i,1,p){ 41 int S1=S^(1<<(i-1)); 42 if (S&(1<<(i-1)) && !vis[S1] && b[S1]) vis[S1]=1,q[++ed]=S1; 43 } 44 } 45 printf("%d ",ans); 46 return 0; 47 }
G.令$fl(l,r)=(m_{l,r}-l)+fl(l,m_{l,r}-1)+fl(m_{l,r}+1,r)$,$fr(l,r)$同理,那么$f(l,r)=fl(l,r)+fr(l,r)+(r-l+1)$,于是考虑求$fr$即可,$fl$类似。
发现对于一个i来说,它对$fr$的贡献等于它到下一个比它大的数的距离(或询问右端点)。
对操作离线,i从小到大枚举,线段树维护当考虑位置1~i的数时,每个询问右端点的答案。
对于一个位置i,它对询问右端点r的贡献是$min(nxt[i]-i-1,r-i)$,这是一个一次函数后加一个常数函数。
线段树内用kx+b来表示一个数即可,打标记是时直接斜率和截距相加。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define ls (x<<1) 6 #define rs (ls|1) 7 #define lson ls,L,mid 8 #define rson rs,mid+1,R 9 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 10 typedef long long ll; 11 using namespace std; 12 13 const int N=1000010; 14 ll ans[N],tag1[N<<2],tag2[N<<2]; 15 int n,m,a[N],stk[N],nxt[N]; 16 struct P{ int l,r,id; ll ans; }q[N]; 17 bool operator <(const P &a,const P &b){ return a.l<b.l; } 18 19 void build(int x,int L,int R){ 20 if (L==R){ tag1[x]=tag2[x]=0; return; } 21 int mid=(L+R)>>1; build(lson); build(rson); 22 } 23 24 void push(int x){ 25 if (tag1[x]) tag1[ls]+=tag1[x],tag1[rs]+=tag1[x],tag1[x]=0; 26 if (tag2[x]) tag2[ls]+=tag2[x],tag2[rs]+=tag2[x],tag2[x]=0; 27 } 28 29 void mdf(int x,int L,int R,int l,int r,int k,int b){ 30 if (L==l && r==R){ tag1[x]+=k; tag2[x]+=b; return; } 31 int mid=(L+R)>>1; push(x); 32 if (r<=mid) mdf(lson,l,r,k,b); 33 else if (l>mid) mdf(rson,l,r,k,b); 34 else mdf(lson,l,mid,k,b),mdf(rson,mid+1,r,k,b); 35 } 36 37 ll que(int x,int L,int R,int k){ 38 if (L==R) return tag1[x]*k+tag2[x]; 39 int mid=(L+R)>>1; push(x); 40 if (k<=mid) return que(lson,k); else return que(rson,k); 41 } 42 43 void solve(){ 44 int top=1; stk[1]=n+1; a[n+1]=n+1; 45 for (int i=n; i; i--){ 46 while (top && a[stk[top]]<a[i]) top--; 47 nxt[i]=stk[top]; stk[++top]=i; 48 } 49 sort(q+1,q+m+1); int r=0; build(1,1,n); 50 rep(i,1,n){ 51 while (r<m && q[r+1].l==i) r++,q[r].ans-=que(1,1,n,q[r].r); 52 mdf(1,1,n,i,nxt[i]-1,1,-i); 53 if (nxt[i]<=n) mdf(1,1,n,nxt[i],n,0,nxt[i]-i-1); 54 } 55 rep(i,1,m) q[i].ans+=que(1,1,n,q[i].r); 56 } 57 58 int main(){ 59 freopen("g.in","r",stdin); 60 freopen("g.out","w",stdout); 61 scanf("%d%d",&n,&m); 62 rep(i,1,n) scanf("%d",&a[i]); 63 rep(i,1,m) scanf("%d",&q[i].l),q[i].id=i; 64 rep(i,1,m) scanf("%d",&q[i].r),q[i].ans=q[i].r-q[i].l+1; 65 solve(); 66 reverse(a+1,a+n+1); 67 rep(i,1,m) q[i].l=n-q[i].l+1,q[i].r=n-q[i].r+1,swap(q[i].l,q[i].r); 68 solve(); 69 rep(i,1,m) ans[q[i].id]=q[i].ans; 70 rep(i,1,m) cout<<ans[i]<<' '; 71 return 0; 72 }