BestCoder Round #73
这场比赛打完后可以找何神玩了orz(orz)*
嘿嘿嘿。输出n/2+m/2即可。
我能说我智商捉鸡想了4min吗?
由于N个点的连通块最少有N-1条边,所以至多删两条。
暴力枚举然后并查集判判即可。
奥妙重重的数位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; }
我选择go die。
考虑用线段树来做。
对于操作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; }