Educational Codeforces Round 60 (Div.2)

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 }
A

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 }
B

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 }
C

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 }
D

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 }
E

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 }
F

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 }
G
原文地址:https://www.cnblogs.com/HocRiser/p/10718907.html