[校内训练20_10_23~25]
Posted greenduck
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[校内训练20_10_23~25]相关的知识,希望对你有一定的参考价值。
1.
标准的卢卡斯定理加数位dp,主要是算C(n,i)*C(n,2*i)。
但由于这题的模数是质数,就不需要考虑很多东西,如:是否超过上限了、是否有连续的进位。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long int ll; 4 const int maxn=1E6+5; 5 ll ans,n,mod; 6 ll fac[maxn],inv[maxn]; 7 int tot,a[66]; 8 inline ll qpow(ll x,ll y) 9 { 10 ll ans=1,base=x; 11 while(y) 12 { 13 if(y&1) 14 ans=ans*base%mod; 15 base=base*base%mod; 16 y>>=1; 17 } 18 return ans; 19 } 20 inline ll C(int x,int y) 21 { 22 if(x<y||x<0||y<0) 23 return 0; 24 return fac[x]*inv[y]%mod*inv[x-y]%mod; 25 } 26 inline void init() 27 { 28 fac[0]=1; 29 for(int i=1;i<mod;++i) 30 fac[i]=fac[i-1]*i%mod; 31 inv[mod-1]=qpow(fac[mod-1],mod-2); 32 for(int i=mod-2;i>=0;--i) 33 inv[i]=inv[i+1]*(i+1)%mod; 34 ll x=n; 35 do 36 { 37 a[++tot]=x%mod; 38 x/=mod; 39 }while(x); 40 reverse(a+1,a+tot+1); 41 } 42 inline ll solve1() 43 { 44 return (qpow(3,n)-1)*qpow(2,mod-2)%mod; 45 } 46 bool vis[28][2]; 47 ll f[28][2]; 48 ll dfs(int pos,int pre)// limit doesn‘t matter 49 { 50 if(vis[pos][pre]) 51 return f[pos][pre]; 52 vis[pos][pre]=1; 53 if(pos==tot) 54 return f[pos][pre]=1; 55 ll s=0; 56 if(pre==0) 57 for(int nxt=0;nxt<=1;++nxt) 58 { 59 int up=(mod-1-nxt)/2; 60 for(int i=0;i<=up;++i) 61 if((2*i>=mod)==nxt) 62 s=(s+dfs(pos+1,nxt)*C(a[pos+1],(2*i+nxt)%mod)%mod*C((2*i+nxt)%mod,i))%mod;// it is correct even if 2*i plus an offset is equal to mod 63 } 64 else 65 for(int nxt=0;nxt<=1;++nxt) 66 { 67 int up=(mod-1-nxt)/2; 68 for(int i=up+1;i<=mod-1;++i) 69 if((2*i>=mod)==nxt) 70 s=(s+dfs(pos+1,nxt)*C(a[pos+1],(2*i+nxt)%mod)%mod*C((2*i+nxt)%mod,i))%mod; 71 } 72 return f[pos][pre]=s; 73 } 74 inline ll solve2() 75 { 76 ll s=dfs(0,0)-1; 77 return s*qpow(2,mod-2)%mod; 78 // for(int i=1;2*i<=n;++i) 79 // s=(s+C(n,2*i)*C(2*i,i)%mod)%mod; 80 // return s*qpow(2,mod-2)%mod; 81 } 82 int main() 83 { 84 ios::sync_with_stdio(false); 85 cin>>n>>mod; 86 init(); 87 ll ans=(solve1()+solve2())%mod; 88 cout<<((qpow(3,n)-ans-1)%mod+mod)%mod<<endl; 89 return 0; 90 }
2.一个数列是好的,当且仅当它第一位是1,并且每次向后移动一位时,前缀max最多增加1。对于每个数字k,求出所有可能的好的数列中它的出现次数的平方的和。n<=5000。
考虑如何计算一对位置的贡献和单独位置的贡献。构造一个好的数列的过程,类似于在二维平面上要么向右移动一步,要么向右上移动一步。其中向右移动一步共有y坐标种数字,向右上移动一步就是钦定放了数字y+1,可以依次设计dp然后前缀和优化。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long int ll; 4 const int maxn=5E3+5; 5 int n,mod; 6 int f[maxn][maxn],g[maxn][maxn][2]; 7 int sum1[maxn][maxn],sum0[maxn][maxn]; 8 int G[55]; 9 inline void write(int x) 10 { 11 int g=0; 12 do{G[++g]=x%10;x/=10;}while(x); 13 for(int i=g;i>=1;--i)putchar(‘0‘+G[i]);putchar(‘ ‘); 14 } 15 inline void add(int&x,int y) 16 { 17 x=(x+y)%mod; 18 } 19 inline int get(int x) 20 { 21 int s=0,h=0; 22 for(int i=1;i<=n;++i) 23 { 24 add(s,sum1[i-1][x]); 25 // for(int j=x;j<=n;++j) 26 // add(s,(ll)f[i-1][j]*g[i][j][1]%mod*2%mod); 27 add(h,(ll)f[i-1][x-1]*g[i][x][1]%mod); 28 if(i==n) 29 break; 30 add(s,sum0[i-1][x]); 31 // for(int j=x;j<=n;++j) 32 // add(s,(ll)f[i-1][j]*g[i][j][0]%mod); 33 add(s,(ll)f[i-1][x-1]*g[i][x][0]%mod); 34 } 35 h=h*2%mod; 36 for(int i=x-1;i<=n;++i) 37 add(s,f[n-1][i]); 38 return (s+h)%mod; 39 } 40 inline void solve() 41 { 42 f[0][0]=1; 43 for(int i=1;i<=n;++i) 44 for(int j=1;j<=i;++j) 45 f[i][j]=(f[i-1][j-1]+(ll)f[i-1][j]*j%mod)%mod; 46 for(int i=1;i<=n;++i) 47 g[n][i][0]=1; 48 for(int i=n;i>1;--i) 49 for(int j=1;j<=i;++j) 50 { 51 add(g[i-1][j][0],(ll)g[i][j][0]*j%mod); 52 add(g[i-1][j][1],g[i][j][0]); 53 add(g[i-1][j][1],(ll)g[i][j][1]*j%mod); 54 55 add(g[i-1][j-1][0],g[i][j][0]); 56 add(g[i-1][j-1][1],g[i][j][1]); 57 } 58 for(int i=1;i<=n;++i) 59 for(int j=i;j>=1;--j) 60 add(sum1[i][j],sum1[i][j+1]+(ll)f[i][j]*g[i+1][j][1]%mod*2%mod); 61 for(int i=1;i<=n;++i) 62 for(int j=i;j>=1;--j) 63 add(sum0[i-1][j],sum0[i-1][j+1]+(ll)f[i-1][j]*g[i][j][0]%mod); 64 for(int i=1;i<=n;++i) 65 write(get(i)); 66 } 67 int main() 68 { 69 ios::sync_with_stdio(false); 70 cin>>n>>mod; 71 solve(); 72 return 0; 73 }
3.斜率优化。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long int ll; 4 typedef long double ld; 5 const ld inf=1E100; 6 int n,a[305],b[305]; 7 ll f[2][305][305]; 8 struct pt 9 { 10 ld x,y; 11 int num; 12 pt(ld a=0,ld b=0,int c=0):x(a),y(b),num(c){} 13 }; 14 inline ld slope(pt A,pt B) 15 { 16 return (A.y-B.y)/(A.x-B.x); 17 } 18 struct AF 19 { 20 pt p[305]; 21 int head,tail; 22 AF() 23 { 24 head=1,tail=0; 25 } 26 void clear() 27 { 28 head=1,tail=0; 29 } 30 inline void add(pt A) 31 { 32 while(head<tail&&slope(p[tail-1],p[tail])>=slope(p[tail],A)) 33 --tail; 34 p[++tail]=A; 35 } 36 inline int ask(ld k) 37 { 38 if(head>tail) 39 return -1; 40 while(head<tail&&slope(p[head],p[head+1])<k) 41 ++head; 42 return p[head].num; 43 } 44 }Q[305]; 45 inline ll s(ll x) 46 { 47 return x*x; 48 } 49 inline void solve() 50 { 51 for(int i=0;i<2;++i) 52 for(int j=0;j<=300;++j) 53 for(int k=0;k<=300;++k) 54 f[i][j][k]=(ll)1000000000000; 55 f[0][0][0]=0; 56 for(int i=1;i<=n;++i) 57 { 58 int p1=i&1,p0=(i&1)^1; 59 for(int j=0;j<=b[i];++j) 60 { 61 Q[j].clear(); 62 for(int k=0;k<=b[i];++k) 63 f[p1][j][k]=(ll)1000000000000; 64 } 65 if(i==1) 66 for(int k=1;k<=b[i];++k) 67 f[p1][k][k]=0; 68 else 69 for(int k=1;k<=b[i];++k) 70 for(int l=1;l<=b[i-1];++l) 71 f[p1][k][k]=min(f[p1][k][k],f[p0][b[i-1]][l]+s(a[i]+k-a[i-1]-l)); 72 for(int j=1;j<=b[i];++j) 73 { 74 for(int k=1;k<j;++k) 75 { 76 int x=Q[j-k].ask(2*k); 77 if(x!=-1) 78 f[p1][j][k]=min(f[p1][j][k],f[p1][j-k][x]+s(k-x)); 79 Q[j].add(pt(k,f[p1][j][k]+k*k,k)); 80 } 81 Q[j].add(pt(j,f[p1][j][j]+j*j,j)); 82 } 83 } 84 ll ans=(ll)10000000000000; 85 int p1=n&1; 86 for(int i=1;i<=b[n];++i) 87 ans=min(ans,f[p1][b[n]][i]); 88 cout<<ans<<endl; 89 } 90 int main() 91 { 92 ios::sync_with_stdio(false); 93 cin>>n; 94 for(int i=1;i<=n;++i) 95 cin>>a[i]>>b[i]; 96 solve(); 97 return 0; 98 }
以上是关于[校内训练20_10_23~25]的主要内容,如果未能解决你的问题,请参考以下文章