some problem

CF1257F Make Them Similar

$solution:$

折半搜索后考虑如何维护两个数组的和,可以将 $A$ 中每个数减 $A_1$ ,$B$ 中每个数被减 $B_1$ ,$map$ 维护一下即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int MAXN=101;
int lowbit(int x){return x&-x;}
int cont(int x){int c=0;while(x) c++,x-=lowbit(x);return c;}
int N,A[MAXN];
vector<int> sta;
map<vector<int> ,int> M;
int main(){
    N=read();for(int i=1;i<=N;i++) A[i]=read();
    for(int i=0;i<(1<<15)-1;i++){
        int cur=cont(i^((A[1]>>15)));sta.clear();
        for(int j=1;j<=N;j++) sta.push_back(cont(i^(A[j]>>15))-cur);
        M[sta]=i;
    }
    int all=((1<<15)-1);
    for(int i=0;i<(1<<15)-1;i++){
        int cur=cont(i^((A[1]&all)));sta.clear();
        for(int j=1;j<=N;j++) sta.push_back(cur-cont(i^(A[j]&all)));
        if(M.count(sta)){
            printf("%d\n",(M[sta]<<15)+i);
            return 0;
        }
    }printf("-1\n");return 0;
}
View Code

CF1257E The Contest

 $solution:$

设 $f_{i,j}$ 表示现在在 $i$ 个数,现在在第 $j$ 段。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int MAXN=2000001;
int col[MAXN],f[MAXN][3],k1,k2,k3,N;
int main(){
    k1=read(),k2=read(),k3=read();N=k1+k2+k3;
    for(int i=1;i<=k1;i++) read();
    for(int i=1;i<=k2;i++) col[read()]=1;
    for(int i=1;i<=k3;i++) col[read()]=2;
    memset(f,127/3,sizeof(f));
    f[0][0]=0;
    for(int i=1;i<=N;i++){
        for(int j=0;j<3;j++){
            for(int k=0;k<=j;k++) f[i][j]=min(f[i][j],f[i-1][k]+(col[i]!=j));
        }
    }
    int Minn=min(f[N][0],min(f[N][1],f[N][2]));
    printf("%d\n",Minn);return 0;
}
View Code

 

CF1268C And Reachability

$solution:$

设 $f_{i,j}$ 表示从 $i$ 点走到离 $i$ 最近并且 $j$ 位上是一的,可以简单递推得到。

时间复杂度 $O(20^2\cdot n)$ 。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int MAXN=300011;
int f[MAXN][21],g[21],n,q,A[MAXN]; 
int main(){
    n=read(),q=read();
    for(int i=1;i<=n;i++) A[i]=read();
    for(int i=0;i<=n+1;i++) for(int j=0;j<=20;j++) f[i][j]=g[j]=n+1;
    for(int i=n;i>=1;i--){
        for(int j=0;j<=20;j++){
            if(A[i]&(1<<j)){
                for(int k=0;k<=20;k++) f[i][k]=min(f[i][k],f[g[j]][k]);
                f[i][j]=i;g[j]=i;
            }
        }
    }
    while(q--){
        int x=read(),y=read();bool ok=0;
        for(int i=0;i<=20;i++) if(A[y]&(1<<i)) ok|=(f[x][i]<=y);
        if(ok){printf("Shi\n");continue;}
        printf("Fou\n");
    }return 0;
}/*
5 5
0 0 1 3 7
1 2
2 2
3 5
4 5
1 5
*/ 
View Code

CF1268B Good Triple

$solution:$

因为 $2k\leq 9$ ,所以直接 $r$ 单调性暴力处理就行。时间复杂度 $O(9n)$ 。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define int long long
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int MAXN=410001;
int L[MAXN],N,A[MAXN];
char str[MAXN];
signed main(){
    scanf("%s",str+1);N=strlen(str+1);
    for(int i=1;i<=N;i++) A[i]=str[i]-'0';
    int ll=0,Ans=0;
    for(int r=1;r<=N;r++){
        for(int i=1;r-2*i>=1;i++){
            if(A[r]==A[r-i]&&A[r-i]==A[r-2*i]){ll=max(ll,r-2*i);break;}
        }
        Ans+=ll;
    }printf("%lld\n",Ans);
}
View Code

 

CSGRound2 逐梦者的初心

$solution:$

考虑将 $S$ 串翻转后1问题就变为了维护多项式系数。$bitset$ 优化即可。

时间复杂度 $O(\dfrac{m^2}{w})$

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<bitset>
using namespace std;
inline int read(){
    int x=0,f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const int N=1000001;
const int MAXN=70001;
int n,m,A[N],Ans[MAXN];
bitset<MAXN> Bit,ve[1001],e;
int main(){
    n=read(),m=read();
    for(int i=1;i<=m;i++) A[i]=read();for(int i=1;i<=n-m;i++) read();
    for(int i=1;i<=m;i++) ve[A[i]][m-i+1]=1;
    n=m;
    for(int i=1;i<=m;i++){
        int opt=read(),x=read();
        if(opt==0) Bit|=(ve[x]<<i);
        else{Bit=(Bit<<1);Bit|=(ve[x]<<1);}
        e[m+i]=1;printf("%d\n",(Bit.flip()&e).count());
        Bit.flip();
    }
    return 0;
}/*
2 2
1 2
1 1
1 3
*/
View Code

CSGRound2 开拓者的卓识

$solution:$

考虑每一位 $a_i$ 对答案的贡献,根据插板原理可以得到。

$$S_{k,1,r}=\sum_{i=1}^r A_i\cdot \dbinom{i+k-2}{k-1}\cdot \dbinom{r-i+k-1}{k-1}\\=A_i\cdot\dfrac{(i+k-2)!}{(k-1)!\cdot(i-1)!}\cdot\dfrac{(r-i+k-1)!}{(k-1)!\cdot(r-i)!}\\=A_i\cdot\dfrac{(i+k-2)!\cdot (r-i+k-1)!}{(i-1)!\cdot(r-i)!}\cdot\dfrac{1}{(k-1)!^2}$$

$NTT$ 优化一下即可,而阶乘的预处理可以分段打表。

时间复杂度 $O(n\log n+n\times blo)$

CF1225E Rock Is Push

$solution:$

设 $f_{i,j,0/1}$ 表示从 $(1,1)$ 走到 $(i,j)$,其中最后一步的走向是右还是下。

则 $f_{i,j,0}=\sum_{e=k}^{j-1} f_{i,e,1}$ ,可以记录前缀和得到一段区间的 $dp$ 和。

而 $k$ 的得到可以因为实现不同,故时间复杂度为 $O(nm\log n)$ 或 $O(nm)$ 。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define int long long
#define mod 1000000007
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int MAXN=2011;
int n,m,f[MAXN][MAXN][2];
/*left 0   down 1*/
char str[MAXN];
int A[MAXN][MAXN],S1[MAXN][MAXN],S2[MAXN][MAXN];
int Qi(int id,int l,int r){/*col*/
    return S1[r][id]-S1[l-1][id];
}
int Qj(int id,int l,int r){/*row*/
    return S2[id][r]-S2[id][l-1];
}
int fS1[MAXN][MAXN],fS2[MAXN][MAXN];
int Mod(int x){return ((x%mod)+mod)%mod;}
signed main(){
//    freopen("maker.in","r",stdin);
    n=read(),m=read();
    for(int i=1;i<=n;i++){
        scanf("%s",str+1);
        for(int j=1;j<=m;j++) A[i][j]=(str[j]=='R');
    }
    if(n==1&&m==1){printf("%lld\n",A[1][1]^1);return 0;}
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) S1[i][j]=S1[i-1][j]+A[i][j];
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) S2[i][j]=S2[i][j-1]+A[i][j];
    f[1][1][0]=f[1][1][1]=1;fS1[1][1]=1,fS2[1][1]=1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(i==1&&j==1) continue;
            int l=1,r=i-1,res=i;
            while(l<=r){
                int mid=l+r>>1;
                if(Qi(j,mid+1,n)<=(n-i)) res=mid,r=mid-1;
                else l=mid+1;
            }
            f[i][j][1]=fS1[i-1][j]-fS1[res-1][j];f[i][j][1]=Mod(f[i][j][1]);
            l=1,r=j-1,res=j;
            while(l<=r){
                int mid=l+r>>1;
                if(Qj(i,mid+1,m)<=(m-j)) res=mid,r=mid-1;
                else l=mid+1; 
            }
            f[i][j][0]=fS2[i][j-1]-fS2[i][res-1];f[i][j][0]=Mod(f[i][j][0]);
            fS1[i][j]=fS1[i-1][j]+f[i][j][0];fS1[i][j]=Mod(fS1[i][j]);
            fS2[i][j]=fS2[i][j-1]+f[i][j][1];fS2[i][j]=Mod(fS2[i][j]);
        }
    }printf("%lld\n",(f[n][m][0]+f[n][m][1])%mod);return 0;
}/*3 3
.RR
...
R..
*/
View Code

 

CF1239D Catowice City

$solution:$

考虑类似于 $2-SAT$ 将必须选择的关系连边,$tarjan$ 后让最开始遍历的强连通分量为 $1$ ,因为 $dfs$ 的顺序易知这是正确的。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int MAXN=1000001;
int n,m,T,col[MAXN],sta[MAXN],num,dfn[MAXN],low[MAXN],Ans0[MAXN],Ans1[MAXN];
vector<int> vec[MAXN];
void Init(){
    num=0;Ans0[0]=0,Ans1[0]=0;
    for(int i=0;i<=n;i++) vec[i].clear();
    for(int i=0;i<=n;i++) col[i]=dfn[i]=low[i]=0;
}
void tarjan(int u){
    dfn[u]=low[u]=++num;sta[++sta[0]]=u;
    int siz=vec[u].size();
    for(int i=0;i<siz;i++){
        int v=vec[u][i];
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }else if(!col[v]) low[u]=min(low[u],low[v]);
    }
    if(dfn[u]==low[u]){
        col[u]=++col[0];
        while(sta[sta[0]]!=u){
            col[sta[sta[0]]]=col[0];
            sta[0]--;
        }sta[0]--;
    }return;
}
int main(){
//    freopen("8.in","r",stdin);
    T=read();
    while(T--){
        n=read(),m=read();
        Init();
        for(int i=1;i<=m;i++){int u=read(),v=read();vec[u].push_back(v);}
        for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
        if(col[0]==1){printf("No\n");continue;}
        for(int i=1;i<=n;i++){
            if(col[i]==1) Ans0[++Ans0[0]]=i;
            else Ans1[++Ans1[0]]=i;
        }
        printf("Yes\n%d %d\n",Ans0[0],Ans1[0]);
        for(int i=1;i<=Ans0[0];i++) printf("%d ",Ans0[i]);printf("\n");
        for(int i=1;i<=Ans1[0];i++) printf("%d ",Ans1[i]);printf("\n");
    }return 0;
}
View Code

CF1244F Chips

$solution:$

考虑若对于 $i$ 来说在 $i-1,i+1$ 有颜色相同的话,那么无论经过多少次操作都可以为本身颜色。

否则,与其相邻的是 $01$ 段,模拟一下即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int MAXN=4000001;
char str[MAXN];
int n,k,A[MAXN],B[MAXN],C[MAXN];
void print(int opt){opt?printf("W"):printf("B");}
int main(){
    n=read(),k=read();
    scanf("%s",str+1);
    for(int i=1;i<=n;i++) A[i]=(str[i]=='W');
    A[0]=A[n],A[n+1]=A[1];
    for(int i=1;i<=n;i++) B[i]=(A[i-1]==A[i]||A[i]==A[i+1]),B[i+n]=B[i];
    bool F=0;for(int i=1;i<=n;i++) F|=B[i];
    if(!F){for(int i=1;i<=n;i++) print(A[i]^(k&1));printf("\n");return 0;}
    int ps=1;for(int i=1;i<=n;i++) if(B[i]) ps=i;
    for(int i=n+1;i<=2*n;i++){if(B[i]) ps=i;C[i-n]=i-ps;}
    for(int i=2*n;i>n;i--) if(B[i]) ps=i;
    for(int i=n;i>=1;i--){if(B[i]) ps=i;C[i]=min(C[i],ps-i);}
    for(int i=1;i<=n;i++){
        if(B[i]) print(A[i]);
        else print(A[i]^(min(k,C[i])&1));
    }printf("\n");return 0;
}
View Code

 

CF1245F Daniel and Spring Cleaning

$solution:$

按维容斥后做简单数位 $dp$ 即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int MAXN=30;
int T,a,b,A[MAXN],B[MAXN],len,f[MAXN][2][2];
int dfs(int ps,int lim1,int lim2){
    if(ps==-1) return 1;
    if(f[ps][lim1][lim2]!=-1) return f[ps][lim1][lim2];
    int e1=(lim1==1)?A[ps]:1,e2=(lim2==1)?B[ps]:1,res=0;
    for(int i=0;i<=e1;i++)
        for(int j=0;j<=e2;j++){
            if(i==1&&j==1) continue;
            res+=dfs(ps-1,lim1&&(i==A[ps]),lim2&&(j==B[ps]));
    }
    return f[ps][lim1][lim2]=res;
}    
int calc(int x,int y){
    if(x<0||y<0) return 0;
    memset(f,-1,sizeof(f));
    len=29;
    for(int i=29;i>=0;i--) A[i]=(x&(1<<i))?1:0;
    for(int i=29;i>=0;i--) B[i]=(y&(1<<i))?1:0;
    return dfs(29,1,1);
} 
signed main(){
//    freopen("4.in","r",stdin);
    T=read();
    while(T--){
        int l=read(),r=read();
        printf("%lld\n",calc(r,r)+calc(l-1,l-1)-2*calc(l-1,r));
    }
    return 0;
}
View Code

 

CF1245E Hyakugoku and Ladders

 $solution:$

设 $f_{i,j}$ 表示从 $(i,j)$ 走到 $(1,1)$ 的期望步数,按题意模拟的转移即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int N=11;
int M[N][N],fro[N*N]; 
double f[N*N];
int main(){
    for(int i=1;i<=10;i++)
        for(int j=1;j<=10;j++){
            if(i&1) M[i][j]=(i-1)*10+j;
            else M[i][j]=(i-1)*10+11-j;
        }
    double sum=0;
    f[1]=0;for(int i=2;i<=6;i++){
        f[i]=(sum+6)/(i-1);
        sum+=f[i];
    }
    for(int i=1;i<=10;i++){
        for(int j=1;j<=10;j++){int x=read();fro[M[i][j]]=M[i-x][j];}
    }
    for(int i=7;i<=100;i++){
        double s=0;
        for(int j=1;j<=6;j++) s+=min(f[i-j],f[fro[i-j]]);
        f[i]=s/6.0+1;
    }
    printf("%.10lf\n",f[100]);return 0;
}
View Code

 

CF1249F Maximum Weight Subset

$solution:$

设 $f_{i,j}$ 表示以 $i$ 号节点为根的子树下距离 $i$ 最近的点至少为 $j$ 的方案数,枚举哪个要选即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int N=211; 
int n,k,f[N][N],head[N],cnt,val[N],son[N];
struct node{
    int u,v,nex;
}x[N<<1];
void add(int u,int v){
    x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++;
}
void dfs(int u,int fath){
    for(int i=head[u];i!=-1;i=x[i].nex){
        if(x[i].v==fath) continue;
        dfs(x[i].v,u);
    }
    son[0]=0;
    for(int i=head[u];i!=-1;i=x[i].nex){
        if(x[i].v==fath) continue;
        son[++son[0]]=x[i].v;
    }
    for(int i=0;i<=k;i++){
        if(i==0){
            f[u][0]=val[u];
            for(int j=1;j<=son[0];j++) f[u][0]+=f[son[j]][k];
            continue;
        }
        for(int j=1;j<=son[0];j++){
            int res=f[son[j]][i-1]; 
            for(int p=1;p<=son[0];p++){
                if(j==p) continue;
                res+=f[son[p]][max(k-i,i-1)];
            }
            f[u][i]=max(f[u][i],res);
        }
    }for(int i=k;i>=0;i--) f[u][i]=max(f[u][i],f[u][i+1]);
}
int main(){
    memset(head,-1,sizeof(head));
    n=read(),k=read();
    for(int i=1;i<=n;i++) val[i]=read();
    for(int i=1;i<n;i++){
        int u=read(),v=read();
        add(u,v),add(v,u);
    }dfs(1,0);
    printf("%d\n",f[1][0]);return 0;
}
View Code

 

posted @ 2019-11-04 19:22  siruiyang_sry  阅读(307)  评论(0编辑  收藏  举报