4.13 BJ集训

T1 Mobitel

题目大意:

一个全是正整数的矩阵,求从左上角到右下角的简单路径有多少条路径上数的乘积$>=K$

思路:

由于整数分块,我们设$f(i,j,k)$表示走到$(i,j)$,$k=K/$(路径上数的乘积),的方案数

然后转移还是正常转移,需要注意把$k--$,因为只能求$>k-1$

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<vector>
 8 #include<queue>
 9 #define rep(i,s,t) for(register int i=(s),i##end=(t);i<=i##end;++i)
10 #define dwn(i,s,t) for(register int i=(s),i##end=(t);i>=i##end;--i)
11 #define ren for(int i=fst[x];i;i=nxt[i])
12 #define ll long long
13 #define MAXN 305
14 #define MOD 1000000007
15 #define pls(a,b) ((a)+(b))%MOD
16 #define mul(a,b) (1LL*(a)*(b))%MOD
17 using namespace std;
18 inline int read()
19 {
20     int x=0,f=1;char ch=getchar();
21     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
22     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
23     return x*f;
24 }
25 int n,m,g[MAXN][MAXN],val[3050],id[1001000];int k;
26 int f[2][MAXN][MAXN*10],tot;
27 void inc(int &x,int y) {x= (x+y>=MOD)?x+y-MOD:x+y;}
28 int main()
29 {
30     freopen("mobitel.in","r",stdin);freopen("mobitel.out","w",stdout);
31     n=read(),m=read(),k=read()-1;rep(i,1,n) rep(j,1,m) g[i][j]=read();int c,pos;
32     rep(i,1,k) pos=k/(k/i),val[++tot]=k/i,i=pos;++tot;rep(i,1,tot) id[val[i]]=i;
33     f[1][1][id[k/g[1][1]]]=1;rep(t,1,n)
34     {
35         c=t&1;rep(i,1,m)
36             rep(j,1,tot) {inc(f[c][i][id[val[j]/g[t][i]]],f[!c][i][j]);
37                 if(i<m) inc(f[c][i+1][id[val[j]/g[t][i+1]]],f[c][i][j]);}
38         memset(f[!c],0,sizeof(f[!c]));
39     }
40     printf("%d\n",f[n&1][m][tot]);
41 }
View Code

 

T2 transport

题目大意:

一个树上,每个点有权值,边权有权值

求有多少对点对满足对于这条路径任意一个前缀都满足点的权值和>边的权值和

思路:

很明显的点分治,对每个分治重心

搜出每一条从重心开始的链需要之前盈余多少权值才能走到,搜出每一条能走到重心的链到根后盈余多少

(第一个分别记录$dis$的最低值,第二个记录最小的一个后缀判断能否走到

排序后双指针,然后容斥一下即可

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<vector>
 8 #include<queue>
 9 #define rep(i,s,t) for(register int i=(s),i##end=(t);i<=i##end;++i)
10 #define dwn(i,s,t) for(register int i=(s),i##end=(t);i>=i##end;--i)
11 #define ren for(int i=fst[x];i;i=nxt[i])
12 #define ll long long
13 #define inf 2139062143
14 #define MAXN 100100
15 #define MOD 1000000007
16 #define pls(a,b) ((a)+(b))%MOD
17 #define mul(a,b) (1LL*(a)*(b))%MOD
18 using namespace std;
19 inline int read()
20 {
21     int x=0,f=1;char ch=getchar();
22     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
23     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
24     return x*f;
25 }
26 int n,m,v[MAXN],fst[MAXN],nxt[MAXN<<1],to[MAXN<<1],val[MAXN<<1];
27 int mx[MAXN],sz[MAXN],Sum,rt,Mx,vis[MAXN],cnt;
28 void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;}
29 void getrt(int x,int pa)
30 {
31     mx[x]=0,sz[x]=1;ren if(to[i]^pa&&!vis[to[i]])
32         getrt(to[i],x),sz[x]+=sz[to[i]],mx[x]=max(mx[x],sz[to[i]]);
33     mx[x]=max(mx[x],Sum-sz[x]);if(mx[x]<Mx) Mx=mx[x],rt=x;
34 }
35 ll g[MAXN],f[MAXN],ans;int ln,len;
36 void get1(int x,int pa,ll mn,ll dis)
37 {
38     g[++len]=mn,dis+=v[x];ren if(to[i]^pa&&!vis[to[i]])
39         get1(to[i],x,min(dis-val[i],mn),dis-val[i]);
40 }
41 void get2(int x,int pa,ll mx,ll dis)
42 {
43     if(v[x]-mx>=0) f[++ln]=v[x]+dis;mx-=v[x],dis+=v[x];ren if(to[i]^pa&&!vis[to[i]])
44         get2(to[i],x,max((ll)val[i],mx+val[i]),dis-val[i]);
45 }
46 void calc(int x,int w,ll res=0)
47 {
48     int tmp=0,pos=ln;sort(g+1,g+len+1);sort(f+1,f+ln+1);
49     rep(i,1,len) {while(pos&&g[i]+f[pos]>=0) tmp++,pos--;res+=tmp;}ans+=res*w;
50 }
51 void div(int x)
52 {
53     vis[x]=1;ln=len=0;get1(x,0,0,0);get2(x,0,0,-v[x]);
54     calc(x,1);ans--;ren if(!vis[to[i]])
55     {
56         ln=len=0;get1(to[i],x,v[x]-val[i],v[x]-val[i]);
57         get2(to[i],x,val[i],-val[i]);calc(to[i],-1);
58     }
59     ren if(!vis[to[i]]) {Sum=sz[to[i]],Mx=n+1;getrt(to[i],x);div(rt);}
60 }
61 int main()
62 {
63     freopen("transport.in","r",stdin);freopen("transport.out","w",stdout);
64     n=read();int a,b,c;rep(i,1,n) v[i]=read();
65     rep(i,2,n) a=read(),b=read(),c=read(),add(a,b,c),add(b,a,c);
66     Sum=n,Mx=n+1;getrt(1,0);div(rt);printf("%lld\n",ans);
67 }
View Code

 

 

T3

题目大意:

$n$个1,要分成$k$段,每一段$[l,r]$的贡献为$\frac{r-l+1}{n-l+1}$,求最大贡献

思路:

这种恰好$k$段的可以二分

每一次分段都加上一个二分出来的这个值,判断最优的段数与$k$的关系来二分

转移的方程是$f_i=f_j+\frac{i-j}{n-j}+mid$ 是一个斜率优化的式子

然后就结束了

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<vector>
 8 #include<queue>
 9 #define rep(i,s,t) for(register int i=(s),i##end=(t);i<=i##end;++i)
10 #define dwn(i,s,t) for(register int i=(s),i##end=(t);i>=i##end;--i)
11 #define ren for(int i=fst[x];i;i=nxt[i])
12 #define ll long long
13 #define db double
14 #define MAXN 100100
15 #define pls(a,b) ((a)+(b))%MOD
16 #define mul(a,b) (1LL*(a)*(b))%MOD
17 using namespace std;
18 inline int read()
19 {
20     int x=0,f=1;char ch=getchar();
21     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
22     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
23     return x*f;
24 }
25 int n,k,pre[MAXN],nxt[MAXN],tm[MAXN],tl,hd,q[MAXN];db f[MAXN];
26 db Y(int i,int j) {return f[i]-f[j]-1.0*i/(n-i)+1.0*j/(n-j);}
27 db X(int i,int j) {return 1.0/(n-i)-1.0/(n-j);}
28 int cheq(db x)
29 {
30     memset(f,0,sizeof(f));q[hd=tl=1]=0;int t;rep(i,1,n)
31     {
32         while(hd<tl&&Y(q[hd],q[hd+1])<=-i*X(q[hd],q[hd+1])) hd++;
33         t=pre[i]=q[hd],f[i]=f[t]+1.0*(i-t)/(n-t)-x,tm[i]=tm[t]+1,pre[i]=t;
34         while(hd<tl&&Y(q[tl-1],q[tl])*X(q[tl],i)<Y(q[tl],i)*X(q[tl-1],q[tl])) tl--;
35         q[++tl]=i;
36     }return tm[n];
37 }
38 int main()
39 {
40     freopen("quiz.in","r",stdin);freopen("quiz.out","w",stdout);
41     n=read(),k=read();db l=0,r=1,mid;
42     for(int t=0,tmp;mid=(l+r)/2.0,t<=100;t++)
43     {
44         if((tmp=cheq(mid))>k) l=mid;
45         else if(tmp<k) r=mid;else break;
46     }
47     printf("%.9lf\n",f[n]+k*mid);
48 }
View Code

 

posted @ 2019-04-13 16:37  jack_yyc  阅读(194)  评论(0编辑  收藏  举报