noi2017解题报告(部分)

10 篇文章 0 订阅
4 篇文章 0 订阅

D1T1:
每30位压成一个int,然后压位线段树就可以过了。

#include <bits/stdc++.h>
#define gc getchar()
#define N 4500009
#define mid (l+r>>1)
#define ll long long
using namespace std;
const int Max=1<<30;
int n,m,t1,t2,t3;
struct node
{
    int val;
    node *lc,*rc;
    void up()
    {
        if (lc->val==rc->val) val=lc->val;
        else val=-1;
    }
    void down()
    {
        if (val!=-1) lc->val=rc->val=val;
    }
    int ins(int l,int r,int x,int y,int ret=0)
    {
        if (l==r)
        {
            val+=y;
            if (val>=Max)
            {
                val-=Max;
                return 1;
            }
            if (val<0)
            {
                val+=Max;
                return -1;
            }
            return 0;
        }
        if (val==0&&l==x&&y==-1)
        {
            val=Max-1;
            return -1;
        }
        if (val==Max-1&&l==x&&y==1)
        {
            val=0;
            return 1;
        }
        down();
        if (x<=mid)
        {
            ret=lc->ins(l,mid,x,y);
            if (ret) ret=rc->ins(mid+1,r,mid+1,ret);
        }
        else ret=rc->ins(mid+1,r,x,y);
        up();
        return ret;
    }
    int get(int l,int r,int x)
    {
        if (l==r) return val;
        down();
        if (x<=mid) return lc->get(l,mid,x);
        else return rc->get(mid+1,r,x);
    }
}a[N],*now=a,*root;
node *build(int l,int r)
{
    node *Now=now++;
    Now->val=0;
    if (l==r) return Now;
    Now->lc=build(l,mid);
    Now->rc=build(mid+1,r);
    return Now;
}
int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    int s=ch-'0';
    while (ch=gc,ch<='9'&&ch>='0') s=s*10+ch-'0';
    return s*x;
}
int main()
{
    m=read(),t1=read(),t2=read(),t3=read();
    n=m+32;
    root=build(0,n);
    while (m--)
    {
        int op=read();
        if (op==1)
        {
            int a=read(),b=read();
            if (a>=0)
            {
                int a1=((ll)a<<(b%30))&(Max-1);
                int a2=a>>(30-b%30);
                int b1=b/30,b2=b1+1;
                if (a1) root->ins(0,n,b1,a1);
                if (a2) root->ins(0,n,b2,a2);
            }
            else
            {
                a=-a;
                int a1=((ll)a<<(b%30))&(Max-1);
                int a2=a>>(30-b%30);
                int b1=b/30,b2=b1+1;
                if (a1) root->ins(0,n,b1,-a1);
                if (a2) root->ins(0,n,b2,-a2);
            }
        }
        else
        {
            int a=read();
            int ans=root->get(0,n,a/30);
            printf("%d\n",(ans>>(a%30))&1);
        }
    }
    return 0;
}

D1T2:
根据miaom大的说法,因为拆开的操作很少,所以每次暴力维护所有 len50 的字符串就可以了, hash+hash 表(注意双哈希)

#include <bits/stdc++.h>
#define gc getchar()
#define ll long long
#define A 7
#define MOD 5614657
#define Mod 44917381
#define mod 998244353
#define N 200009
#define M 10000009
#define DEBUG 0
#define debug() cerr<<"wrong"<<endl
using namespace std;
int n,m,a[N],fa[N],son[N],b[M],p[55][2];
struct HASH
{
    #define MM 10000010
    int number,first[MOD];
    struct edge
    {
        int y,next,val;
        edge(int y=0,int next=0,int val=0):y(y),next(next),val(val){}
    }e[MM];
    inline void add(int x,int y)
    {
        e[++number]=edge(y,first[x],1);
        first[x]=number;
    }
    inline void ins(int x,int y)
    {
        for (int i=first[x];i;i=e[i].next)
            if (e[i].y==y)
            {
                e[i].val++;
                return;
            }
        add(x,y);
    }
    inline void del(int x,int y)
    {
        for (int i=first[x];i;i=e[i].next)
            if (e[i].y==y)
            {
                e[i].val--;
                return;
            }
    }
    inline int find(int x,int y)
    {
        for (int i=first[x];i;i=e[i].next)
            if (e[i].y==y) return e[i].val;
        return 0;
    }
}ha;
inline int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    int s=ch-'0';
    while (ch=gc,ch<='9'&&ch>='0') s=s*10+ch-'0';
    return s*x;
}
inline void link(int x,int y)
{
    fa[y]=x,son[x]=y;
    int last=x,next=y,len1=1,len2=1,len=0;
    for (int i=1;i<=48&&fa[last];i++) last=fa[last],len1++;
    for (int i=1;i<=48&&son[next];i++) next=son[next],len2++;
    for (int i=1;i<=len1+len2;i++)
        b[++len]=a[last],last=son[last];
    for (int i=1;i<=len1;i++)
    {
        int now=0,Now=0;
        for (int j=i;j<=len1;j++)
        {
            now=(now*A%MOD+b[j])%MOD;
            Now=(Now*A%Mod+b[j])%Mod;
        }
        for (int j=len1+1;j-i+1<=50&&j<=len;j++)
        {
            now=(now*A%MOD+b[j])%MOD;
            Now=(Now*A%Mod+b[j])%Mod;
            ha.ins(now,Now);
        }
    }
}
inline void cut(int x,int y)
{
    int last=x,next=y,len1=1,len2=1,len=0;
    for (int i=1;i<=48&&fa[last];i++) last=fa[last],len1++;
    for (int i=1;i<=48&&son[next];i++) next=son[next],len2++;
    for (int i=1;i<=len1+len2;i++)
        b[++len]=a[last],last=son[last];
    for (int i=1;i<=len1;i++)
    {
        int now=0,Now=0;
        for (int j=i;j<=len1;j++)
        {
            now=(now*A%MOD+b[j])%MOD;
            Now=(Now*A%Mod+b[j])%Mod;
        }
        for (int j=len1+1;j-i+1<=50&&j<=len;j++)
        {
            now=(now*A%MOD+b[j])%MOD;
            Now=(Now*A%Mod+b[j])%Mod;
            ha.del(now,Now);
        }
    }
    fa[y]=son[x]=0;
}
inline int solve()
{
    int len=0,k,now=0,Now=0;
    char ch;
    while (ch=gc,ch<'1'||ch>'6');
    while (ch!=' ') b[++len]=ch-'0',ch=gc;
    k=read();
    for (int i=1;i<=k;i++)
    {
        now=(now*A%MOD+b[i])%MOD;
        Now=(Now*A%Mod+b[i])%Mod;
    }
    int ans=ha.find(now,Now);
    for (int i=2;i<=len-k+1;i++)
    {
        now=(now-(ll)b[i-1]*p[k-1][0]%MOD+MOD)%MOD;
        now=(now*A%MOD+b[i+k-1])%MOD;
        Now=(Now-(ll)b[i-1]*p[k-1][1]%Mod+Mod)%Mod;
        Now=(Now*A%Mod+b[i+k-1])%Mod;
        ans=(ll)ans*ha.find(now,Now)%mod;
        if (ans==0) break;
    }
    return ans;
}
int main()
{
    if (DEBUG)
    {
        freopen("queue25.in","r",stdin);
        freopen("queue25.out","w",stdout);
    }
    n=read(),m=read();
    for (int i=1;i<=n;i++) a[i]=read(),ha.ins(a[i],a[i]);
    p[0][0]=p[0][1]=1;
    for (int i=1;i<=50;i++)
        p[i][0]=p[i-1][0]*A%MOD,p[i][1]=p[i-1][1]*A%Mod;
    while (m--)
    {
        int op=read();
        if (op==1)
        {
            int x=read(),y=read();
            link(x,y);
        }
        if (op==2)
        {
            int x=read(),y=son[x];
            cut(x,y);
        }
        if (op==3) printf("%d\n",solve());
    }
    return 0;
}

然而有些网站跑得慢,过不了,所以就需要sam来维护。

#include <bits/stdc++.h>
#define gc getchar()
#define ll long long
#define mod 998244353
#define N 4500009
#define M 10000009
#define DEBUG 1
#define debug() cerr<<"wrong"<<endl
using namespace std;
int n,m,a[N],fa[N],Son[N],b[M];
int son[N][6],fail[N],w[N];
int cnt;
void init()
{
    cnt=1;
    for (int i=0;i<6;i++) son[cnt][i]=0;
    fail[cnt]=w[cnt]=0;
}
int go(int x,int k)
{
    if (!son[x][k]) fail[son[x][k]=++cnt]=son[fail[x]][k];
    return son[x][k];
}
inline int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    int s=ch-'0';
    while (ch=gc,ch<='9'&&ch>='0') s=s*10+ch-'0';
    return s*x;
}
inline void link(int x,int y)
{
    fa[y]=x,Son[x]=y;
    int last=x,next=y,len1=1,len2=1,len=0;
    for (int i=1;i<=48&&fa[last];i++) last=fa[last],len1++;
    for (int i=1;i<=48&&Son[next];i++) next=Son[next],len2++;
    for (int i=1;i<=len1+len2;i++)
        b[++len]=a[last],last=Son[last];
    for (int i=2,j,k;i<=50&&i<=len;i++)//i=added string's length
    {
        int now=1;
        for (j=max(1,len1-i+2),k=i;--k;j++)
            now=son[now][b[j]];
        for (;j<=len&&j-i+1<=len1;j++)
        {
            now=go(now,b[j]);
            w[now]++;
            now=fail[now];
        }
    }
}
inline void cut(int x,int y)
{
    int last=x,next=y,len1=1,len2=1,len=0;
    for (int i=1;i<=48&&fa[last];i++) last=fa[last],len1++;
    for (int i=1;i<=48&&Son[next];i++) next=Son[next],len2++;
    for (int i=1;i<=len1+len2;i++)
        b[++len]=a[last],last=Son[last];
    for (int i=1,k=x;i<50&&k;k=fa[k],i++)//i=deleted string's length
    {
        int now=1;
        for (int p=k,j=1;j<=50&&p;j++,p=Son[p])
        {
            now=son[now][a[p]];
            if (j>i) w[now]--;//p is behind x
        }
    }
    fa[y]=Son[x]=0;
}
inline int solve()
{
    int len=0,k;
    char ch;
    while (ch=gc,ch<'1'||ch>'6');
    while (ch!=' ') b[++len]=ch-'1',ch=gc;
    k=read();
    int ans=1,now=1;
    for (int i=1;i<=len;i++)
    {
        if (!son[now][b[i]])
        {
            ans=0;
            break;
        }
        now=son[now][b[i]];
        if (i>=k) ans=(ll)ans*w[now]%mod,now=fail[now];
    }
    return ans;
}
int main()
{
    if (DEBUG)
    {
        freopen("queue25.in","r",stdin);
        freopen("queue25.out","w",stdout);
    }
    n=read(),m=read();
    init();
    for (int i=1;i<=n;i++)
    {
        a[i]=read()-1;
        if (!son[1][a[i]]) fail[son[1][a[i]]=++cnt]=1;
        w[son[1][a[i]]]++;
    }
    while (m--)
    {
        int op=read();
        if (op==1)
        {
            int x=read(),y=read();
            link(x,y);
        }
        if (op==2)
        {
            int x=read(),y=Son[x];
            cut(x,y);
        }
        if (op==3) printf("%d\n",solve());
    }
    return 0;
}

D1T3:
原问题可以转化为 Sdangerk 的答案
首先 dp[i][j] 表示宽度为 j ,前i1行全是 danger ,最后 sdangerk 的概率。
所以上面的答案就是 dp[1][n]
然后这个可以比较容易 dp 转移。
然后可以算出 21001 dp ,这是 O(k2logk) 的。
然后线性其次递推,用一些姿势可以算出第 1 行的答案。
(反正我还不会)

#include <bits/stdc++.h>
#define ll long long
#define mod 998244353
#define N 2009
using namespace std;
int n,k,x,y,dp[N][N],pw[N],p,f[N],g[N],a[N],b[N],c[N];
int ksm(int x,int y,int ret=1)
{
    for (;y;y>>=1,x=(ll)x*x%mod)
        if (y&1) ret=(ll)ret*x%mod;
    return ret;
}
void mul(int n,int *a,int *b)
{
    memset(c,0,sizeof(c));
    for (int i=0;i<=n;i++)
        for (int j=0;j<=n;j++)
            c[i+j]=(c[i+j]+(ll)a[i]*b[j]%mod)%mod;
    for (int i=2*n;i>n;i--)
        for (int j=1;j<=n+1;j++)
            c[i-j]=(c[i-j]+(ll)c[i]*g[j]%mod)%mod;
    for (int i=0;i<=n;i++) a[i]=c[i];
}
int solve(int limit)
{
    if (!limit) return ksm(mod+1-p,n);
    memset(dp,0,sizeof(dp));
    dp[limit+1][0]=1;
    dp[limit+1][1]=pw[limit];
    for (int i=limit;i;i--)
    {
        for (int j=0;j<=limit;j++) dp[i][j]=dp[i+1][j];
        for (int j=1;(i-1)*j<=limit&&j<=limit;j++)
            for (int x=1;x<=j;x++)
                dp[i][j]=(dp[i][j]+(ll)dp[i+1][x-1]*dp[i][j-x]%mod*pw[i-1]%mod)%mod;
    }
    if (n<=limit) return dp[1][n];
    for (int i=1;i<=limit+1;i++) g[i]=(ll)dp[2][i-1]*(mod+1-p)%mod;
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    a[0]=1,b[1]=1;
    for (int i=n+1;i;i>>=1)
    {
        if (i&1) mul(limit,a,b);
        mul(limit,b,b);
    }//calculate the coefficients
    int ans=0;
    memset(f,0,sizeof(f));
    f[0]=ksm(mod+1-p,mod-2);//f[0]=1/(1-p)
    for (int i=1;i<=limit+1;i++)
        f[i]=dp[1][i-1];
    for (int i=0;i<=limit;i++) ans=(ans+(ll)f[i]*a[i]%mod)%mod;
    return ans;
}
int main()
{
    scanf("%d%d%d%d",&n,&k,&x,&y);
    p=(ll)x*ksm(y,mod-2)%mod;
    pw[0]=mod+1-p;
    for (int i=1;i<N;i++) pw[i]=(ll)pw[i-1]*p%mod;
    printf("%d\n",(solve(k)-solve(k-1)+mod)%mod);
    return 0;
}

D2T1:
就是一道2-sat简单题。。(然而我没做出来)
枚举x a 还是b地图,然后直接2-sat模板上就好了。
时间复杂度 O(2d(n+m))
(据说 3d 在现场也可以过)

#include <bits/stdc++.h>
#define gc getchar()
#define N 50009
#define mid (l+r>>1)
#define ll long long
using namespace std;
const char ans[3][2]={{'B','C'},{'A','C'},{'A','B'}};
int n,d,pos[10],num,mp[N],m,first[N<<1],number;
int dfn[N<<1],low[N<<1],sta[N<<1],top,vis[N<<1],col[N<<1],col_num,cnt;
int First[N<<1],Number,ds[N<<1],choose[N<<1],Ans[N];
vector<int> opp[N<<1],color[N<<1];
queue<int> q;
struct in_edge
{
    int x,hx,y,hy;
}Ed[N<<1];
struct edge
{
    int from,to,next;
    void add(int x,int y)
    {
        from=x,to=y,next=first[x],first[x]=number;
    }
}e[N<<2];
struct Edge
{
    int from,to,next;
    void add(int x,int y)
    {
        from=x,to=y,next=First[x],First[x]=Number;
    }
}E[N<<2];
int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    int s=ch-'0';
    while (ch=gc,ch<='9'&&ch>='0') s=s*10+ch-'0';
    return s*x;
}
void get_map()
{
    for (int i=1;i<=(n<<1);i++) First[i]=first[i]=0;
    number=Number=0;
    for (int i=1;i<=m;i++)
    {
        int x,y;
        if (mp[Ed[i].x]<2) x=(Ed[i].hx==2);
        else x=(Ed[i].hx==1);
        x+=2*Ed[i].x-1;
        if (mp[Ed[i].y]<2) y=(Ed[i].hy==2);
        else y=(Ed[i].hy==1);
        y+=2*Ed[i].y-1;
        if (Ed[i].x==Ed[i].y)
        {
            if (Ed[i].hx==Ed[i].hy) continue;
            else 
            {
                if (Ed[i].hx==mp[Ed[i].x]) continue;
                else
                    e[++number].add(x,4*Ed[i].x-x-1);
            }
        }
        if (mp[Ed[i].x]==Ed[i].hx) continue;
        if (mp[Ed[i].y]==Ed[i].hy)
        {
            e[++number].add(x,4*Ed[i].x-x-1);
            continue;
        }
        e[++number].add(x,y);
        e[++number].add(4*Ed[i].y-y-1,4*Ed[i].x-x-1);
    }
}
void Tarjan(int x)
{
    dfn[x]=++cnt;
    low[x]=cnt;
    vis[x]=1;
    sta[++top]=x;
    for (int i=first[x];i;i=e[i].next)
    {
        int temp=e[i].to;
        if (!dfn[temp])
        {
            Tarjan(temp);
            low[x]=min(low[x],low[temp]);
        }
        else
            if (vis[temp]) low[x]=min(low[x],dfn[temp]);
    }
    if (dfn[x]==low[x])
    {
        vis[x]=0;
        col[x]=++col_num;
        color[col_num].push_back(x);
        while (sta[top]!=x)
        {
            col[sta[top]]=col_num;
            color[col_num].push_back(sta[top]);
            vis[sta[top--]]=0;
        }
        top--;
    }
}
bool solve()
{
    top=cnt=col_num=0;
    for (int i=1;i<=(n<<1);i++)
        choose[i]=ds[i]=dfn[i]=low[i]=vis[i]=0;
    for (int i=1;i<=(n<<1);i++)
        opp[i].clear(),color[i].clear();
    for (int i=1;i<=(n<<1);i++)
        if (!dfn[i]) Tarjan(i);
    for (int i=1;i<=number;i++)
        if (col[e[i].to]!=col[e[i].from])
        {
            E[++Number].add(col[e[i].to],col[e[i].from]);
            ds[col[e[i].from]]++;
        }
    for (int i=1;i<=n;i++)
    {
        if (col[i*2-1]==col[i*2]) return 0;
        opp[col[i*2-1]].push_back(col[i*2]);
        opp[col[i*2]].push_back(col[i*2-1]);
    }
    while (!q.empty()) q.pop();
    for (int i=1;i<=col_num;i++)
        if (ds[i]==0) q.push(i);
    for (int l=1;l<=col_num;l++)
    {
        int now=q.front();
        //cout<<now<<endl;
        q.pop();
        if (!choose[now])
        {
            choose[now]=1;
            for (int i=0;i<color[now].size();i++)
                Ans[(color[now][i]+1)>>1]=(color[now][i]+1)&1;
            for (int i=0;i<opp[now].size();i++)
                choose[opp[now][i]]=2;
        }
        for (int i=First[now];i;i=E[i].next)
            if (!(--ds[E[i].to])) q.push(E[i].to);
    }
    return 1;
}
void print()
{
    for (int i=1;i<=n;i++) putchar(ans[mp[i]][Ans[i]]);
    puts("");
}
int main()
{
    n=read(),d=read();
    for (int i=1;i<=n;i++)
    {
        char ch;
        while (ch=gc,ch!='x'&&ch!='a'&&ch!='b'&&ch!='c');
        if (ch=='x') pos[++num]=i;
        else mp[i]=ch-'a';
    }
    m=read();
    for (int i=1;i<=m;i++)
    {
        char ch;
        Ed[i].x=read();
        while (ch=gc,ch!='A'&&ch!='B'&&ch!='C');
        Ed[i].hx=ch-'A';
        Ed[i].y=read();
        while (ch=gc,ch!='A'&&ch!='B'&&ch!='C');
        Ed[i].hy=ch-'A';
    }
    for (int now=0;now<(1<<d);now++)
    {
        for (int i=1;i<=d;i++) mp[pos[i]]=(now>>(i-1))&1;
        get_map();
        if (solve())
        {
            print();
            return 0;
        }
    }
    puts("-1");
    return 0;
}

D2T2&&D2T3:
一道费用流神题,一道计算几何神题,反正我不会写。。。(T2可能还有一丝希望)
(未完待续)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值