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 }
View Code

 

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 }
View Code

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 }    
View Code

 

转载于:https://www.cnblogs.com/FOXYY/p/8671332.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值