2018/3/29
前两天的题还没有改完,先写一发今天的题解
T1 BZOJ [5215] 商场购物
这个题还是比较水的,就是f[i][j]表示到第i个商店,花费了j元的方案数,然后可以发现,这个东西在[1,m]内都是可以转移出来的,然后剩下的用挡板法(C(n+m-1,m-1))进行剩余的计数就好了。
1 #include <cmath> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <iostream> 6 #include <algorithm> 7 using namespace std; 8 typedef long long LL; 9 void ot(){cout<<"***"<<endl;} 10 const int maxM=310; 11 const int maxn=5000010; 12 const int mod=(int)1e9+7; 13 int read(){ 14 int x=0,fg=1; char c=getchar(); 15 while(c<'0' || c>'9'){if(c=='-') fg=-1; c=getchar();} 16 while(c>='0'&&c<='9'){x = x*10 + c-'0'; c=getchar();} 17 return x*fg; 18 } 19 int n,m,K; 20 int w[maxM]; 21 LL ksm(LL a,int b){ 22 LL ret=1; 23 while(b){ 24 if(b&1) ret*=a,ret%=mod; 25 b>>=1; a*=a; a%=mod; 26 } 27 return ret; 28 } 29 const int Mx=(int)1e7; 30 LL fac[Mx+10],inv_fac[Mx+10]; 31 LL C(int a,int b){ 32 if(a<b) return 0; 33 return fac[a]*inv_fac[b]%mod*inv_fac[a-b]%mod; 34 } 35 LL f[2][90010]; 36 void work2(){ 37 fac[0]=1; for(int i=1;i<=Mx;i++) fac[i]=fac[i-1]*i%mod; 38 inv_fac[0]=1; inv_fac[Mx]=ksm(fac[Mx],mod-2); 39 for(int i=Mx-1;i;i--) inv_fac[i]=inv_fac[i+1]*(i+1)%mod; 40 f[0][0]=1; int lim1,lim2,sum=0; 41 for(int i=1;i<=min(90000,K);i++) f[0][i]=1; 42 int lst=0,now=1; 43 for(int i=1;i<=m;i++){ 44 memset(f[now],0,sizeof(f[now])); 45 if(i<=m) lim1=sum+w[i],lim2=w[i]; else lim1=K,lim2=K; 46 for(int j=0;j<=lim1;j++){ 47 f[now][j]=(f[lst][j]-(j>lim2?f[lst][j-w[i]-1]:0))%mod; 48 } 49 if(i<=m) sum+=w[i]; 50 if(i==m) break; 51 for(int j=1;j<=sum+w[i+1];j++){ 52 f[now][j]=(f[now][j]+f[now][j-1])%mod; 53 } 54 now^=1,lst^=1; 55 } 56 LL ans=0; 57 if(n==m) ans=f[now][K]; 58 else for(int i=0;i<=min(sum,K);i++){ 59 ans=(ans + f[now][i]*C(K-i+n-m-1,n-m-1)%mod)%mod; 60 } 61 if(ans<0) ans+=mod; 62 cout<<ans<<endl; 63 } 64 int main(){ 65 n=read(); m=read(); K=read(); 66 for(int i=1;i<=m;i++) w[i]=read(); 67 work2(); 68 }
T2 BZOJ [5216] 公路建设
这个题用到了用到了有的凸包题的思想,就是可以直接建一颗线段树,然后每一个节点存的就是对应区间内的边构成最小生成树的树边,然后查询的时候就把对应区间里的边都提出来在跑一遍最小生成树就好了。由于树边不超过n个,所以空间和时间复杂度都是对的
1 #include <cmath> 2 #include <vector> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cstring> 6 #include <iostream> 7 #include <algorithm> 8 # define PB push_back 9 using namespace std; 10 const int maxM=(int)1e5+10; 11 const int maxn=110; 12 int read(){ 13 int x=0,fg=1; char c=getchar(); 14 while(c<'0' || c>'9'){if(c=='-') fg=-1; c=getchar();} 15 while(c>='0'&&c<='9'){x = x*10 + c-'0'; c=getchar();} 16 return x*fg; 17 } 18 int n,m,Q; 19 struct edge{int u,v,w;}g[maxM]; 20 bool cmp1(const edge &a,const edge &b){return a.w<b.w;} 21 void init(){ 22 n=read(); m=read(); Q=read(); 23 for(int i=1;i<=m;i++){ 24 g[i].u=read(); g[i].v=read(); g[i].w=read(); 25 } 26 } 27 int fa[maxn]; 28 int find_fa(int x){ 29 if(x==fa[x]) return x; 30 return fa[x]=find_fa(fa[x]); 31 } 32 vector<int> ve[maxM*4]; 33 int sta[maxM],cnt[maxM*4],q[maxM]; 34 int head; 35 void Make_tree(int now,int l,int r){ 36 int a,b; 37 for(int i=1;i<=n;i++) fa[i]=i; 38 for(int i=1;i<=head;i++){ 39 a=find_fa(g[sta[i]].u),b=find_fa(g[sta[i]].v); 40 if(a!=b) fa[b]=a,ve[now].PB(sta[i]); 41 } 42 } 43 void Build(int now,int l,int r){ 44 if(l==r){ve[now].PB(l); return;} 45 int mid=(l+r)>>1; 46 Build(now<<1,l,mid); Build(now<<1|1,mid+1,r); 47 head=0; int t1=0,t2=0,ls=now<<1,rs=now<<1|1; 48 while(t1<ve[ls].size()&&t2<ve[rs].size()){ 49 if(g[ve[ls][t1]].w<g[ve[rs][t2]].w) sta[++head]=ve[ls][t1++]; 50 else sta[++head]=ve[rs][t2++]; 51 } 52 while(t1<ve[ls].size()) sta[++head]=ve[ls][t1++]; 53 while(t2<ve[rs].size()) sta[++head]=ve[rs][t2++]; 54 Make_tree(now,l,r); 55 } 56 void query(int now,int l,int r,int left,int right){ 57 if(left<=l && r<=right){ 58 cnt[now]=l-1; for(int i=0;i<ve[now].size();i++) q[++cnt[now]]=ve[now][i]; 59 return; 60 } 61 int mid=(l+r)>>1,ls=now<<1,rs=now<<1|1; 62 cnt[ls]=l-1,cnt[rs]=mid; 63 if(left<=mid) query(ls,l,mid,left,right); 64 if(right>mid) query(rs,mid+1,r,left,right); 65 head=0; int t1=l,t2=mid+1; 66 while(t1<=cnt[ls] && t2<=cnt[rs]) 67 if(g[q[t1]].w<g[q[t2]].w) sta[++head]=q[t1++]; 68 else sta[++head]=q[t2++]; 69 while(t1<=cnt[ls]) sta[++head]=q[t1++]; 70 while(t2<=cnt[rs]) sta[++head]=q[t2++]; 71 cnt[now]=l-1; 72 for(int i=1;i<=head;i++) q[++cnt[now]]=sta[i]; 73 } 74 void find_ans(int l,int r){ 75 query(1,1,m,l,r); 76 for(int i=1;i<=n;i++) fa[i]=i; 77 int a,b,ans=0; 78 for(int i=1;i<=cnt[1];i++){ 79 a=find_fa(g[q[i]].u),b=find_fa(g[q[i]].v); 80 if(a!=b) fa[b]=a,ans+=g[q[i]].w; 81 } 82 printf("%d\n",ans); 83 } 84 void work2(){ 85 Build(1,1,m); 86 int l,r; 87 for(int i=1;i<=Q;i++){ 88 l=read(); r=read(); 89 find_ans(l,r); 90 } 91 } 92 int main(){ 93 init(); 94 work2(); 95 }
T3 BZOJ [5217] 航海舰队
这个题还是比较神的
既然所有的战舰都是保持相对位置不变的,那么我们就可以考虑整体的考虑它们。我们先把整张地图一行一行首尾相接构成一个串S,然后如果是 # 那么对应位是1,否则的话就是0,然后我们类似的也把战舰所在的最小矩形构成一个字符串T,如果是o对应位就是1,否则是0,但是要注意的就是开头和结尾一定都是战舰,也就是矩形的两头没有用的要舍弃,然后如果矩形的长度不够m要用0补上,保证和原图构成的串题配的正确性,然后我们发现,如果在S中,有一个长度为|T|的子串和T对应为乘积都是0,那么就说明这个舰队能放上去,那么我们把T反过来,和S FFT就可以加速这个过程,然后得到的卷积的结果的每一个数或者说每一个点实际上都代表以某一个点位左上角的一个矩形,但是虽然有的地方能放下整个舰队,但是这个舰队并不能移动过去,那么就需要我们BFS一发来筛出实际能到达的左上角。 然后我们怎么统计答案,我们就是还是把原来的图构成一个串,这次是能成为左上角的位置是1,然后和舰队的那个矩形的正着建的串做一下卷积,然后对应位不是0的就可以做成贡献。然后这么正着卷为什么是对的呢?就是我们可以设表示能到达的左上角多项式为f,然后正着建的多项式是d,我们可以一点一点的向右挪动d,如果d[1]对应的f是1并且f[j]对应到d上也是1,那么这个点就是能做出贡献的,然后这个其实就是一个卷积的形式。
1 #include <cmath> 2 #include <queue> 3 #include <cstdio> 4 #include <cstring> 5 #include <cstdlib> 6 #include <iostream> 7 #include <algorithm> 8 # define fir first 9 # define sec second 10 # define MP make_pair 11 using namespace std; 12 typedef int LL; 13 //typedef long long LL; 14 const int mod=998244353; 15 const int g_=3; 16 const int maxn=710; 17 const int maxlen=maxn*maxn*8; /////////// 18 long long ksm(long long a,int b){ 19 long long ret=1; 20 while(b){ 21 if(b&1) ret*=a,ret%=mod; 22 b>>=1; a*=a; a%=mod; 23 } 24 return ret; 25 } 26 int N,rev[maxlen]; 27 void ntt(LL *a,int tp){ 28 for(int i=0;i<N;i++) if(i<rev[i]) swap(a[i],a[rev[i]]); 29 LL w,wn,t; 30 for(int k=2;k<=N;k<<=1){ 31 wn=ksm(g_,tp==1 ? (mod-1)/k : mod-1-(mod-1)/k); 32 for(int j=0;j<N;j+=k){ 33 w=1; 34 for(int i=0;i<(k>>1);i++,w=1ll*w*wn%mod){ 35 t=1ll*a[i+j+(k>>1)]*w%mod; 36 a[i+j+(k>>1)]=(a[i+j]-t)%mod; 37 a[i+j]=(a[i+j]+t)%mod; 38 } 39 } 40 } 41 if(tp==-1){ 42 int inv=ksm(N,mod-2); 43 for(int i=0;i<N;i++) a[i]=(1ll*a[i]*inv%mod+mod)%mod; 44 } 45 } 46 void NTT(LL *a,LL *b,LL *c,int lenth,LL &tt){ 47 for(N=1;N<lenth;N<<=1); tt=N; 48 for(int i=0;i<N;i++) 49 if(i&1) rev[i]=(rev[i>>1]>>1)|(N>>1); 50 else rev[i]=rev[i>>1]>>1; 51 ntt(a,1); ntt(b,1); 52 for(int i=0;i<N;i++) c[i]=1ll*a[i]*b[i]%mod; 53 ntt(c,-1); 54 } 55 char s[maxn][maxn]; 56 int n,m; 57 void init(){ 58 scanf("%d%d",&n,&m); 59 for(int i=1;i<=n;i++){ 60 scanf("%s",s[i]+1); 61 } 62 } 63 int mn_x,mx_x,mn_y,mx_y,L,H; 64 LL mp[maxlen],c_mp; 65 LL sp[maxlen],c_sp; 66 LL tg[maxlen],c_tg; 67 int id[maxn][maxn]; 68 void make_mp_sp(){ 69 mn_x=n+100; mx_x=-1; 70 mn_y=n+100; mx_y=-1; 71 for(int i=1;i<=n;i++) 72 for(int j=1;j<=m;j++) 73 if(s[i][j]=='o') 74 mn_x=min(mn_x,i),mx_x=max(mx_x,i), 75 mn_y=min(mn_y,j),mx_y=max(mx_y,j); 76 L=mx_y-mn_y+1; H=mx_x-mn_x+1; 77 int lim1,lim2; 78 for(int i=mx_x;i>=mn_x;i--){ 79 lim1=m,lim2=1; 80 if(i==mx_x) lim1=mx_y; 81 if(i==mn_x) lim2=mn_y; 82 for(int j=lim1;j>=lim2;j--){ 83 sp[c_sp++]=(s[i][j]=='o'); 84 85 } 86 } 87 88 for(int i=1;i<=n;i++) 89 for(int j=1;j<=m;j++) 90 mp[c_mp++]=(s[i][j]=='#'),id[i][j]=c_mp+c_sp-2; 91 } 92 typedef pair<int,int> pii; 93 queue<pii> q; 94 bool vis[maxn][maxn]; 95 void Push(int x,int y){ 96 if(x>=1 && x<=n-H+1 && y>=1 && y<=m-L+1 && !vis[x][y] && !tg[id[x][y]]){ 97 vis[x][y]=1; q.push(MP(x,y)); 98 } 99 } 100 void bfs(){ 101 q.push(MP(mn_x,mn_y)); 102 vis[mn_x][mn_y]=1; 103 int x,y; 104 while(!q.empty()){ 105 pii k=q.front(); q.pop(); 106 x=k.fir,y=k.sec; 107 Push(x,y+1); Push(x,y-1); 108 Push(x+1,y); Push(x-1,y); 109 } 110 } 111 LL ab[maxlen],c_ab; 112 LL ct[maxlen],c_ct; 113 LL as[maxlen],c_as; 114 void make_ab_ct(){ 115 for(int i=1;i<=n;i++) 116 for(int j=1;j<=m;j++) 117 ab[c_ab++]=vis[i][j]; 118 int lim1,lim2; 119 for(int i=mn_x;i<=mx_x;i++){ 120 lim1=1; lim2=m; 121 if(i==mn_x) lim1=mn_y; 122 if(i==mx_x) lim2=mx_y; 123 for(int j=lim1;j<=lim2;j++) 124 ct[c_ct++]=(s[i][j]=='o'); 125 } 126 } 127 //#include <ctime> 128 int main(){ 129 // freopen("sailing9.in","r",stdin); 130 // freopen("2.out","w",stdout); 131 init(); 132 make_mp_sp(); 133 // cerr<<clock()<<endl; 134 NTT(mp,sp,tg,c_mp,c_tg); 135 // cerr<<clock()<<endl; 136 bfs(); 137 make_ab_ct(); 138 NTT(ab,ct,as,c_ab,c_as); 139 int ans=0; 140 for(int i=0;i<n*m;i++) if(as[i]) ans++; 141 printf("%d\n",ans); 142 // cerr<<clock()<<endl; 143 }