zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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
    ",f[n]+k*mid);
    48 }
    View Code
  • 相关阅读:
    利用数组创建的顺序表实现各种功能
    poj3181 Dollar Dayz
    【网络协议】TCP的流量控制机制
    6.6.1 F# 中函数调用的类型判断
    oracle ORA-06550
    为基于 x86 的 Android* 游戏选择合适的引擎
    linux下apache https 虚拟主机配置
    Hibernate学习笔记(六) — Hibernate的二级缓存
    08_Android中的SimpleAdapter的使用
    【从零学习openCV】IOS7人脸识别实战
  • 原文地址:https://www.cnblogs.com/yyc-jack-0920/p/10701707.html
Copyright © 2011-2022 走看看