12.1 模拟赛

(貌似是远古大坑了

T1 bzoj 4737 组合数问题

题目大意:

给定 $n,m$ 求有多少个$C_n^m$整除$k$ $(n,m \le 10^{18})$

思路:

考虑如何计算组合数 使用lucas只有在lucas递归过程中n<m才会产生0

因此我们考虑把$n,m$按照k进制分解 只要中间某一位n<m即满足题意

可以数位dp 由于统计补集比较简单 所以统计补集即中间所有数$m \le n$

$dp \space i \space j \space k$表示到了第i位 是否卡在了$n,m$的边界上 转移非常好转移

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<queue>
 8 #include<vector>
 9 #include<map>
10 #define ll long long
11 #define inf 2139062143
12 #define rep(i,s,t) for(int i=(s);i<=(t);++i)
13 #define dwn(i,s,t) for(int i=(s);i>=(t);--i)
14 #define ren for(int i=fst[x];i;i=nxt[i])
15 #define Fill(x,t) memset(x,t,sizeof(x))
16 #define MAXN 100
17 #define MOD 1000000007
18 using namespace std;
19 inline ll read()
20 {
21     ll 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 ll n,m,T,p,dp[MAXN][2][2],a[MAXN],la,b[MAXN],lb,ans;
27 ll q_pow(ll bas,ll t)
28 {
29     ll res=1;
30     for(;t;t>>=1,(bas*=bas)%=MOD)
31         if(t&1) (res*=bas)%=MOD;
32     return res;
33 }
34 inline ll inv(ll x) {return q_pow(x,MOD-2);}
35 int main()
36 {
37     T=read(),p=read();ll inv2=inv(2);int lx,ly;
38     while(T--)
39     {
40         n=read(),m=read(),m=min(n,m),la=lb=0LL;Fill(dp,0);Fill(a,0);Fill(b,0);
41         ans=(((((m%MOD)*((m+1)%MOD))%MOD)*inv2)%MOD+(((n-m+1)%MOD)*((m+1)%MOD))%MOD)%MOD;
42         while(n) a[++la]=n%p,n/=p;while(m) b[++lb]=m%p,m/=p;
43         dp[la+1][1][1]=1;
44         dwn(i,la,1) rep(j,0,1) rep(k,0,1)
45             if(dp[i+1][j][k])
46             {
47                 if(j) lx=a[i];else lx=p-1;
48                 if(k) ly=b[i];else ly=p-1;
49                 rep(x,0,lx) rep(y,0,min(ly,x)) (dp[i][j&(x==a[i])][k&(y==b[i])]+=dp[i+1][j][k])%=MOD;
50             }
51         rep(i,0,1) rep(j,0,1) (ans+=MOD-dp[1][i][j])%=MOD;
52         printf("%lld\n",ans);
53     }
54 }
View Code

 

T2 bzoj 4738 汽水

题目大意:

在树上求一条路径使得这个路径的边权平均值最接近$K$ 求这个最小差值

思路:

这种东西很容易想到点分治,我们对于所有初始边权都减去$K$,这样就是求最接近$0$的路径

对于分治重心内的所有路径,维护三个值:路径总长,路径上边数,来自哪一个子树

我们对于总长排序后可以二分一个值,判断能否存在两个路径拼起来差值满足mid

把式子转化为$sum-num \times x$其中$x$为二分出的mid 这样只要分别$check (\pm mid)$

写两个check即可

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<vector>
 8 #include<queue>
 9 #include<map>
10 #include<set>
11 #include<complex>
12 #include<iomanip>
13 #define Fill(a,x) memset(a,x,sizeof(a))
14 #define rep(i,s,t) for(register int i=(s),i__end=(t);i<=i__end;++i)
15 #define dwn(i,s,t) for(register int i=(s),i__end=(t);i>=i__end;--i)
16 #define ren for(int i=fst[x];i;i=nxt[i])
17 #define inf 1LL<<60
18 #define ll long long
19 #define ull unsigned long long
20 #define MAXN 50100
21 #define MOD 998244353
22 using namespace std;
23 inline ll read()
24 {
25     ll x=0,f=1;char ch=getchar();
26     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
27     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
28     return x*f;
29 }
30 struct data {int num,bl;ll val;}g[MAXN],A,B;
31 bool operator < (data a,data b) {return a.val<b.val;}
32 int n,fst[MAXN],nxt[MAXN<<1],to[MAXN<<1],cnt,sz[MAXN],mx[MAXN],Sum,Mx,rt,len,vis[MAXN];
33 ll val[MAXN<<1],K,ans=inf;
34 void add(int u,int v,ll w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;}
35 void getrt(int x,int pa)
36 {
37     mx[x]=0,sz[x]=1;ren if(to[i]^pa&&!vis[to[i]]) getrt(to[i],x),sz[x]+=sz[to[i]],mx[x]=max(mx[x],sz[to[i]]);
38     mx[x]=max(mx[x],Sum-sz[x]);if(mx[x]<Mx) Mx=mx[x],rt=x;
39 }
40 void Get(int x,int pa,int dep,int frm,ll dis)
41 {
42     g[++len]=(data){dep,frm,dis};
43     ren if(to[i]^pa&&!vis[to[i]]) Get(to[i],x,dep+1,frm,dis+val[i]);
44 }
45 int pos;
46 void upd(data x)
47 {
48     if(B<x) return ;
49     if(x<A) {if(x.bl!=A.bl) B=A;A=x;}else if(x.bl!=A.bl) B=x;
50 }
51 int cheq(ll x)
52 {
53     A=B=(data){0,0,inf};int j=pos-1;
54     rep(i,pos,len)
55     {
56         for(;j&&g[i].val+g[j].val>=0;j--) upd((data){0,g[j].bl,g[j].val-x*g[j].num});
57         if((A.bl==g[i].bl?B.val:A.val)<(ll)x*g[i].num-g[i].val) return 1;
58         upd((data){0,g[i].bl,g[i].val-x*g[i].num});
59     }
60     return 0;
61 }
62 int cheQ(ll x)
63 {
64     A=B=(data){0,0,inf};int j=pos;
65     dwn(i,pos-1,1)
66     {
67         for(;j<=len&&g[i].val+g[j].val<0;j++) upd((data){0,g[j].bl,(ll)x*g[j].num-g[j].val});
68         if((A.bl==g[i].bl?B.val:A.val)<g[i].val-x*g[i].num) return 1;
69         upd((data){0,g[i].bl,(ll)x*g[i].num-g[i].val});
70     }
71     return 0;
72 }
73 void calc(int x)
74 {
75     vis[x]=1,len=0;g[++len]=(data){0,0,0};ren if(!vis[to[i]]) Get(to[i],x,1,to[i],val[i]);
76     sort(g+1,g+len+1);
77     pos=lower_bound(g+1,g+len+1,(data){0,0,0})-g;ll l=1,r=ans;
78     for(ll mid;mid=l+r>>1,l<=r;) if(cheq(mid)||cheQ(-mid)) r=mid-1;else l=mid+1;
79     ans=min(ans,l-1);
80 }
81 void div(int x)
82 {
83     calc(x);ren if(!vis[to[i]]) Sum=sz[to[i]],Mx=n+1,getrt(to[i],x),div(rt);
84 }
85 int main()
86 {
87     n=read(),K=read();int a,b;ll c;
88     rep(i,2,n) a=read(),b=read(),c=read(),ans=min(ans,abs(c-K)),add(a,b,c-K),add(b,a,c-K);
89     Sum=n,Mx=n+1;getrt(1,0);div(rt);printf("%lld\n",ans);
90 }
View Code

 

 

T3 定向越野(由于是计算几何所以咕咕咕了

posted @ 2018-12-01 18:43  jack_yyc  阅读(190)  评论(0编辑  收藏  举报