BestCoder Round #73

这场比赛打完后可以找何神玩了orz(orz)*

T1Rikka with Chess

嘿嘿嘿。输出n/2+m/2即可。

我能说我智商捉鸡想了4min吗?

 

T2Rikka with Graph

由于N个点的连通块最少有N-1条边,所以至多删两条。

暴力枚举然后并查集判判即可。

 

T3Rikka with Array

奥妙重重的数位dp。

设f[i][j][d1][d2][d3]表示前i位,x1与x2的数位差为j。大小关系如下:

d1=0 x1<x2
d1=1 x1=x2
d1=2 x1>x2
d2=0 x1<=n
d2=1 x1>n
d3=0 x2<=n
d3=1 x2>n

然后滚动数组DP一下。

#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i;i=next[i])
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;
}
typedef long long ll;
const int mod=998244353;
const int maxn=1010;
struct bign {
    int s[maxn],len;
    bign operator = (const char* a) {
        memset(s,0,sizeof(s));len=strlen(a);
        rep(i,0,len-1) s[i]=a[len-i-1]-'0';
    }
    void operator /= (int b) {
        int x=0;
        dwn(i,len-1,0) {
            int v=s[i]+x;
            s[i]=v/2;
            x=(v%2)*10;
        }
        while(!s[len-1]&&len>1) len--;
    }
    void print() {
        dwn(i,len-1,0) printf("%d",s[i]);
        puts("");
    }
}N;
char s[maxn];
int bit[maxn];
ll f[2][maxn*2][3][2][2];
void solve() {
    scanf("%s",s);N=s;int n=0;
    while(N.s[0]||N.len!=1) bit[++n]=N.s[0]&1,N/=2;
    memset(f,0,sizeof(f));
    int cur=0;f[0][n][1][0][0]=1;
    rep(i,0,n-1) {
        cur^=1;memset(f[cur],0,sizeof(f[cur]));
        rep(j,-i+n,i+n) rep(d1,0,2) rep(d2,0,1) rep(d3,0,1) {
            ll& ans=f[cur^1][j][d1][d2][d3];
            (f[cur][j][d1][bit[i+1]?0:d2][bit[i+1]?0:d3]+=ans)%=mod;
            (f[cur][j][d1][(!bit[i+1])?1:d2][(!bit[i+1])?1:d3]+=ans)%=mod;
            (f[cur][j+1][2][(!bit[i+1])?1:d2][bit[i+1]?0:d3]+=ans)%=mod;
            (f[cur][j-1][0][bit[i+1]?0:d2][(!bit[i+1])?1:d3]+=ans)%=mod;
        }
    }
    ll ans=0;
    rep(i,n+1,2*n) (ans+=f[cur][i][0][0][0])%=mod;
    printf("%lld\n",ans);
}
int main() {
    int T=read();
    while(T--) solve();
    return 0;
}
View Code

 

T4:Rikka with Sequence

我选择go die。

 

T5:Rikka with Phi

考虑用线段树来做。

对于操作1,暴力变换带标记且不全为1的区间。

对于操作2,在线段树上打标记。

对于操作3,线段树上直接查询。

等等,我们写程序要讲道理对不对。

我们发现对于一个[1,10^7]的数x,最多执行logx次操作1x就变成了1。

我们可以进行势能分析,初始势能为nlogx。

对于操作1,每变换一次势能-1。

对于操作2,至多增加log^2n的势能。

对于操作3,时间复杂度恒定O(logn)

所以总时间复杂度O(nlog^2n)

#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
const int BufferSize=1<<16;
char buffer[BufferSize],*head,*tail;
inline char Getchar() {
    if(head==tail) {
        int l=fread(buffer,1,BufferSize,stdin);
        tail=(head=buffer)+l;
    }
    return *head++;
}
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;
}
typedef long long ll;
const int N=10000010;
const int maxn=300010;
int vis[N],phi[N],pri[N/10],cnt;
void gen(int n) {
    phi[1]=1;
    rep(i,2,n) {
        if(!vis[i]) pri[++cnt]=i,phi[i]=i-1;
        rep(j,1,cnt) {
            if(i*pri[j]>n) break;
            vis[i*pri[j]]=1;
            if(i%pri[j]==0) {phi[i*pri[j]]=phi[i]*pri[j];break;}
            phi[i*pri[j]]=phi[i]*(pri[j]-1);
        }
    }
}
ll sumv[maxn*4],is[maxn*4],setv[maxn*4];
void pushdown(int o,int l,int r) {
    if(setv[o]) {
        int lc=o<<1,rc=lc|1,mid=l+r>>1;
        setv[lc]=setv[rc]=setv[o];
        is[lc]=is[rc]=1;
        sumv[lc]=setv[o]*(mid-l+1);
        sumv[rc]=setv[o]*(r-mid);
        setv[o]=0;
    }
}
void maintain(int o,int l,int r) {
    int lc=o<<1,rc=lc|1;
    if(setv[o]) sumv[o]=(r-l+1)*setv[o],is[o]=(setv[o]!=1);
    else sumv[o]=sumv[lc]+sumv[rc],is[o]=is[lc]|is[rc];
}
void update(int o,int l,int r,int ql,int qr,int v) {
    if(ql<=l&&r<=qr) setv[o]=v;
    else {
        pushdown(o,l,r);
        int lc=o<<1,rc=lc|1,mid=l+r>>1;
        if(ql<=mid) update(lc,l,mid,ql,qr,v);
        if(qr>mid) update(rc,mid+1,r,ql,qr,v);
    }
    maintain(o,l,r);
}
void update2(int o,int l,int r,int ql,int qr) {
    if(ql<=l&&r<=qr&&setv[o]) setv[o]=phi[setv[o]];
    else {
        pushdown(o,l,r);
        int lc=o<<1,rc=lc|1,mid=l+r>>1;
        if(ql<=mid&&is[lc]) update2(lc,l,mid,ql,qr);
        if(qr>mid&&is[rc]) update2(rc,mid+1,r,ql,qr);
    }
    maintain(o,l,r);
}
void build(int o,int l,int r) {
    sumv[o]=is[o]=setv[o]=0;
    if(l==r) setv[o]=read();
    else {
        int lc=o<<1,rc=lc|1,mid=l+r>>1;
        build(lc,l,mid);build(rc,mid+1,r);
    }
    maintain(o,l,r);
}
ll query(int o,int l,int r,int ql,int qr) {
    if(ql<=l&&r<=qr) return sumv[o];
    pushdown(o,l,r);
    int lc=o<<1,rc=lc|1,mid=l+r>>1;ll ans=0;
    if(ql<=mid) ans+=query(lc,l,mid,ql,qr);
    if(qr>mid) ans+=query(rc,mid+1,r,ql,qr);
    return ans;
}
void solve() {
    int n=read(),m=read();
    build(1,1,n);
    while(m--) {
        int t=read(),l=read(),r=read();
        if(t==1) update2(1,1,n,l,r);
        else if(t==2) update(1,1,n,l,r,read());
        else printf("%lld\n",query(1,1,n,l,r));
    }
}
int main() {
    gen(10000000);
    dwn(T,read(),1) solve();
    return 0;
}
View Code

 

posted @ 2016-02-23 21:24  wzj_is_a_juruo  阅读(189)  评论(0编辑  收藏  举报