contest15

来源:互联网 发布:北塔软件规模 编辑:程序博客网 时间:2024/06/07 22:26

[比赛链接]https://vjudge.net/contest/168929#problem)

比赛征程

  • Y : solved in the contest
  • A : solved after contest
  • SY : solving
# A B C D E contest0 Y Y A A A

比赛中解决的问题

A

Problem description

给你四个正整数a,b,c,d,问你存不存在时刻,使得(a+k1 * b)与 (c+k2 * s d)相等?k1,k2为正整数。

Data Limit:a,b,c,d<=100  Time Limit: 1s

Solution

1、直接暴枚到30000000 O(30000000)*小常数
2、枚举k1到10000 O(10000)*小常数
3、扩展欧几里德算法

Code

using namespace std;#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<cstdlib>int x,y;int gcd(int x,int y){    return y==0?x:gcd(y,x%y);}void exgcd(int a,int b,int &x,int &y){    if(b==0){x=1;y=0;return;} exgcd(b,a%b,x,y);int xx=x,yy=y;y=(xx-(a/b)*yy);x=yy;}int a,b,c,d;int main(){    cin>>a>>b>>c>>d;    int it=gcd(a,c);    if(((d-b)/it)*it!=(d-b)){puts("-1");return 0;}    exgcd(a,c,x,y);    x*=(d-b)/it;    y*=(d-b)/it;//  cout<<x<<" "<<y<<endl;    it=(a*c)/it;    int t1=it/a,t2=it/c;    while(y>0)    {        y-=t2;x+=t1;    }    while(abs(y)>t2)    {        y+=t2;x-=t1;    }    while(x<0) {x+=t1;y-=t2;}    cout<<x*a+b<<endl;}

B

Problem description

每个宇宙来两个人,这两个人一叛徒一忠臣,他们报了一些组,当某一组全为叛徒时,机会取消,问是否有这样的可能性。

Data Limit:n <= 1e4  Time Limit: 2s

Solution

直接模拟即可。每次每组若出现两个来自同一个平行宇宙的,说明该组没危险。

Code

    scanf("%d",&n);cin>>m;    for(int i=1;i<=m;i++)    {        scanf("%d",&num);        memset(vis,0,sizeof(vis));        bool flag=0;        for(int j=1;j<=num;j++)        {            scanf("%d",&pp[j]);        }        for(int j=1;j<=num;j++) if(pp[j]>0) vis[pp[j]]=1;        for(int j=1;j<=num;j++) if(pp[j]<0) if(vis[-pp[j]]){flag=1;break;}        if(flag);else {puts("YES");return 0;}    }    puts("NO");

赛后补题

C

Problem description

两个人玩游戏,每个人有一个集合,两人轮流游戏,每次他们能让怪兽顺时针走他们选出的自己集合中的数步(可以多次使用),某人走完后怪兽到了结束点就赢了,问对于怪兽在每个位置(不在
游戏结束点)某人先手是否必胜/必输或有策略无限循环?

Data Limit:n <= 7e3  Time Limit: 4s

Solution

这种博弈问题看到题目就两种思路:
1、SG函数,这道题很难用
2、广搜的赢点输点DP,一方不能再走为输
对于一个赢点,那么所有对方能转移到他的点都为输点。
对于一个点,如果所有他能够出发到达的点都是对手的赢点,那么该点为输点
这是一大类套路DP,我要多做这方面的题。

Code

using namespace std;#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<queue>#include<map>#define N 7001struct NODE{    int x,y,z;}ind;map<int,string>M;int k[2],s[N][2];int n,m;bool b[N][3];int ans[N][3];int du[N][3];queue<NODE>q;void p(int x,int y,int z){    if(b[x][y]) return;    ind.x=x;ind.y=y;ind.z=z;//  cout<<x<<" "<<y<<" "<<z<<endl;    b[x][y]=1;q.push(ind);ans[x][y]=z;}int main(){    scanf("%d",&n);    for(int i=0;i<=n;i++) for(int j=0;j<2;j++) ans[i][j]=3;    for(int i=0;i<2;i++)    {        scanf("%d",&k[i]);        for(int j=1;j<=k[i];j++) scanf("%d",&s[j][i]);     }    for(int i=0;i<2;i++)    {        for(int j=1;j<=n;j++)        {            du[j][i]=k[i];        }    }    M[0]="Win";M[1]="Lose";M[3]="Loop";    p(0,0,1);p(0,1,1);    while(!q.empty())    {        NODE hh=q.front();q.pop();        int x=hh.x,y=hh.y,z=hh.z;        if(z)        for(int i=1;i<=k[y^1];i++) p((x-s[i][y^1]+n*5)%n,y^1,0);        else        {            for(int i=1;i<=k[y^1];i++)            {                du[(x-s[i][y^1]+n*5)%n][y^1]--;                if(!du[(x-s[i][y^1]+n*5)%n][y^1])                p((x-s[i][y^1]+n*5)%n,y^1,1);            }        }    }    for(int i=0;i<2;i++)    {        for(int j=1;j<=n-1;j++)        {            cout<<M[ans[j][i]]<<" ";        }        puts("");    }}

D

Problem description

有三种类型的道路,1.花费x,从u->v.
2、花费x,从u->[L,R]中任意一点。
3、花费x,从[L,R]中任意一点->u;
求s,到所有点的最少花费

Data Limit:n <= 1e5  Time Limit: 2s

Solution

这题是虚拟建建节点的方法,利用类似线段树的构造,把边数优化到nlogn
这种题用单项边汇。

Code

using namespace std;#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#include<queue>#define r(x) scanf("%lld",&x)#define forw(i,x) for(long long i=fir[x];i;i=ne[i])#define N 3000001long long root1,n,m,root2;long long ty,x,u,v,l,r,w;long long ne[N],dis[N],fir[N],to[N],C[N],cnt,tot;bool inq[N];long long s;void add(long long x,long long y,long long z){    ne[++cnt]=fir[x];fir[x]=cnt;to[cnt]=y;C[cnt]=z;}long long L[N],R[N];long long lc[N],rc[N],sz;queue<long long>q;long long build1(long long l,long long r){    if(l==r) {L[l]=l;R[l]=r;return l;}    ++sz;    long long mid=(l+r)>>1;    long long no=sz;    add(no,lc[no]=build1(l,mid),0);add(no,rc[no]=build1(mid+1,r),0);    L[no]=l;R[no]=r;    return no;}long long build2(long long l,long long r){    if(l==r) {L[l]=l;R[l]=r;return l;}    ++sz;long long mid=(l+r)>>1;    long long no=sz;    add(lc[no]=build2(l,mid),no,0);add(rc[no]=build2(mid+1,r),no,0);    L[no]=l;R[no]=r;    return no;}void ADD1(long long no,long long u,long long l,long long r,long long w){    if(L[no]==l&&R[no]==r) {add(u,no,w);return;}    long long mid=(L[no]+R[no])>>1;    if(l>mid)    ADD1(rc[no],u,l,r,w);else    if(r<=mid)    ADD1(lc[no],u,l,r,w);else    {        ADD1(lc[no],u,l,mid,w);        ADD1(rc[no],u,mid+1,r,w);        return;    }}void ADD2(long long no,long long u,long long l,long long r,long long w){    if(L[no]==l&&R[no]==r) {add(no,u,w);return;}    long long mid=(L[no]+R[no])>>1;    if(l>mid)    ADD2(rc[no],u,l,r,w);else    if(r<=mid)    ADD2(lc[no],u,l,r,w);else    {        ADD2(lc[no],u,l,mid,w);        ADD2(rc[no],u,mid+1,r,w);        return;    }}void SPFA(long long s){    q.push(s);inq[s]=1;dis[s]=0;    while(!q.empty())    {        long long ind=q.front();q.pop();inq[ind]=0;        forw(i,ind)        {            long long V=to[i];            if(dis[V]>dis[ind]+C[i])            {                dis[V]=dis[ind]+C[i];                if(!inq[V])                {                    inq[V]=1;                    q.push(V);                }            }        }    }}main(){    cin>>n>>m>>s;sz=n;    root1=build1(1,n);    root2=build2(1,n);    for(long long i=1;i<=m;i++)    {        cin>>ty;        if(ty==1)         {            r(u);r(v);r(w);add(u,v,w);        }        if(ty==2)         {            r(v);r(l);r(r);r(w);            ADD1(root1,v,l,r,w);        }        if(ty==3)        {            r(v);r(l);r(r);r(w);            ADD2(root2,v,l,r,w);        }    }    for(long long i=1;i<=sz;i++) dis[i]=1e18;    SPFA(s);    for(long long i=1;i<=n;i++)    {        if(dis[i]<1e18) cout<<dis[i]<<' ';else cout<<"-1 ";    }}

E

Problem description

一个有n个颜色的排列,对于特定的k,求将原序列分成最少的连续的段数,使每段的颜色数小于等于k。输出k=1~n的答案。

Data Limit:n <= 1e5  Time Limit: 2s

Solution

1、如果k=l的个数等于k=r的个数那么k=l~r这么多数答案均相同,这样就每次二分+模拟就可以了。调和级数约为logn.所以O(nlog^2n)

2、这类区间的题,可以用切割区间然后按左端点排序从左到右查找更新的方法解决,用树状数组维护从i~j内的不同颜色数,然后二分最远位置即可。
特殊处理就是nxt数组记录下一个这种颜色,以便查询完i后删除i。很好的方法,对离线问题值得借鉴!

##Code1

using namespace std;#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#define N 200001int n,color[100001];int ans[N];int confuse[100001];bool num[100001];int cal(int x){    if(confuse[x]) return confuse[x];    for(int l=1;l<=n;)    {        int cnt=0;        int f=l;        while(cnt<x&&f<=n)        {            if(!num[color[f]])cnt++;            num[color[f++]]=1;        }        while(num[color[f]]&&f<=n)f++;        if(!num[color[f]])f--;        for(int k=l;k<=f;k++) num[color[k]]=0;        confuse[x]++;l=f+1;    }    return confuse[x];}void doit(int l,int r){    if(l>r) return;    int rr=r,ll=l+1;    int an=l;    while(ll<=rr)    {        int mid=(ll+rr)>>1;        if(cal(mid)==cal(l))        {            ll=mid+1;an=mid;        }        else        rr=mid-1;    }    for(int i=l;i<=an;i++)     {        ans[i]=cal(l);    }    doit(an+1,r);}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++) scanf("%d",&color[i]);    doit(1,n);    for(int i=1;i<=n;i++)    {        cout<<ans[i]<<" ";    }}

##Code1

using namespace std;#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<vector>#define N 300001#define F(i,a,b) for(int i=a;i<=b;i++)#define lowbit(x) (x&(-x))int c[N],S[N];int n,m;vector<int>q[N];int col[N];void add(int x,int v){    for(int i=x;i<=n;i+=lowbit(i))    S[i]+=v;}int get(int k){    int res=0;    for(int i=16;i>=0;i--)    {        int x=(1<<i);        if(res+x<=n)        if(S[res+x]<=k)        {            res+=x;            k-=S[res];        }    }    return res;}int num[N];int ans[N];int nxt[N];int main(){    scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%d",&c[i]);    for(int i=1;i<=n;i++)    {        q[1].push_back(i);        if(!num[c[i]])        {            num[c[i]]=i;            add(i,1);        }        else         {            nxt[num[c[i]]]=i;            num[c[i]]=i;        }    }    F(i,1,n)    {        int hh=q[i].size();        for(int j=0;j<hh;j++)        {            int xx=get(q[i][j]);            ans[q[i][j]]++;            q[xx+1].push_back(q[i][j]);        }         hh=nxt[i];        add(i,-1);if(hh>0) add(hh,1);    }    for(int i=1;i<=n;i++) cout<<ans[i]<<" ";}
原创粉丝点击