2017/10/25模拟赛总结

来源:互联网 发布:skype6 下载 mac 编辑:程序博客网 时间:2024/06/08 07:36

T1T2找自信 T3打出GG

T1 矩阵染色

其实所有操作是满足一个拓扑序的
在满足拓扑序的情况下找字典序最小的情况
数据较小 可以直接暴力查找当前的合法操作
从后往前找 考虑撤销操作
如果当前行去掉还存在的点全是黑色 那么就可以撤销
一列为白同理
由于是从后往前 每次要找最大的
用前缀和优化
O(n2)

#include<bits/stdc++.h>using namespace std;#define N 510char str[N],ans1[N<<1];int a[N][N],ans2[N<<1],sumx1[N],sumx0[N],sumy1[N],sumy0[N];int main(){    int n,i,j,h=0;    scanf("%d",&n);    for (i=1;i<=n;i++){        scanf("%s",str);        for (j=1;j<=n;j++)            if (str[j-1]=='W') a[i][j]=1,sumx1[i]++,sumy1[j]++;            else sumx0[i]++,sumy0[j]++;    }    int cnt=n*n;    while (cnt){        bool find=0;        for (i=n;i;i--){            if (!sumx0[i]) continue;            if (!sumx1[i]){                ans1[++h]='R';                ans2[h]=i;                find=1;                for (j=1;j<=n;j++)                    if (a[i][j]==0){                        cnt--;                        sumx0[i]--;                        sumy0[j]--;                        a[i][j]=-1;                    }                break;            }        }        if (find) continue;        for (j=n;j;j--){            if (!sumy1[j]) continue;            if (!sumy0[j]){                ans1[++h]='C';                ans2[h]=j;                find=1;                for (i=1;i<=n;i++)                    if (a[i][j]==1){                        cnt--;                        sumx1[i]--;                        sumy1[j]--;                        a[i][j]=-1;                    }                break;            }        }        if (!find){            printf("No solution\n");            return 0;        }    }    for (i=h;i;i--) printf("%c%d ",ans1[i],ans2[i]);    return 0;}

T2 接竹竿

LibreOJ 507

不需要考虑嵌套 因为嵌套的话直接消大的就好了
那么dpi表示前i张 最多得到多少分
对于每个点可以暴力枚举前面同一颜色的转移
dpi=max{dpj1+sumisumj1},coluri=colurj其中sum为前缀和
那么只需要对于每个颜色存dpisumi的最大值即可
O(n)

#include<bits/stdc++.h>using namespace std;#define N 1000010#define INF (0x3f3f3f3f3f3f3f3f)void rd(int &x){    char c;x=0;    while (c=getchar(),c<48);    do x=(x<<1)+(x<<3)+(c^48);    while (c=getchar(),c>=48);}long long sum[N],P[N],dp[N];int a[N],b[N],n,k;int main(){    int i;    scanf("%d%d",&n,&k);    for (i=1;i<=n;i++) rd(a[i]);    for (i=1;i<=n;i++) rd(b[i]),sum[i]=sum[i-1]+b[i];    for (i=1;i<=k;i++) P[i]=-INF;    for (i=1;i<=n;i++){        dp[i]=max(dp[i-1],P[a[i]]+sum[i]);        P[a[i]]=max(P[a[i]],dp[i-1]-sum[i-1]);    }    printf("%lld\n",dp[n]);    return 0;}

T3 失控的未来交通工具

LibreOJ 508
这个题显然和环有关系
可以发现一条路径长度可以表示为某条路径加上所有环长度gcd的若干倍
因为总是存在一个方案可以使这种情况成立(在环上绕圈等)
由于需要知道一条路径的长度 不妨构建一棵树
可以用并查集维护一个点到根的距离
回答询问可以用exgcd
x,x+b,...,x+(c1)bx,x+b,...,x+(c1)b中有多少个g的倍数
g的倍数每隔 ggcd(b,g)个出现一次
于是只要求出某一次出现的位置即可
就是用exgcd解x+kb=0(modg)
O(q(αn+logw))

#include<bits/stdc++.h>using namespace std;#define N 1000010inline void rd(int &x){    char c;x=0;    while (c=getchar(),c<48);    do x=(x<<1)+(x<<3)+(c^48);    while (c=getchar(),c>=48);}inline void pt(int x){    if (!x) putchar('0');    else{         int s[10],t;        for (t=0;x;x/=10) s[t++]=x%10;        while (t) putchar(s[--t]^48);    }    putchar('\n');}int n,m;int fa[N],dis[N],G[N];int get(int x){    if (fa[x]==x) return x;    int t=fa[x];    fa[x]=get(t);    dis[x]=(dis[x]+dis[t])%m;    return fa[x];}int gcd(int x,int y){    return !y?x:gcd(y,x%y);}int ex_gcd(int a,int b,int &x,int &y){    if (!b){        x=1,y=0;        return a;    }    int t=ex_gcd(b,a%b,y,x);    y-=a/b*x;    return t;}void merge(int x,int y,int z){    int p=get(x),q=get(y);    if (p==q){        int l=(dis[x]+dis[y])%m;        G[p]=gcd(gcd(G[p],2*z%m),z+l);    }else{        fa[p]=q;        dis[p]=(1LL*z+m-dis[x]+m-dis[y])%m;        G[q]=gcd(gcd(G[p],G[q]),2*dis[p]%m);    }}int cal(int a,int b,int c){    int x,y;    ex_gcd(a,c,x,y);    long long d=1LL*a*x+1LL*c*y;    if (b%d) return -1;    int t=c/d;    return (x*(b/d)%t+t)%t;}int query(int x,int y,int a,int b,int c){    int p=get(x),q=get(y);    if (p==q){        int g=gcd(G[p],m);        int k=cal(b%g,((dis[x]+dis[y]-a)%g+g)%g,g);        if (~k && k<c) return (c-k-1)/(g/gcd(g,b))+1;    }    return 0;}int main(){    int q,i;    rd(n),rd(m),rd(q);    for (i=1;i<=n;i++) fa[i]=i;    for (i=1;i<=q;i++){        int op,x,y,a,b,c;        rd(op),rd(x),rd(y),rd(a);        if (op==1) merge(x,y,a);        else{            rd(b),rd(c);            pt(query(x,y,a,b,c));        }    }    return 0;}

Date:2017/10/26
By CalvinJin

原创粉丝点击