今天写了一天的题,并没有复习。
12.25
DP
1.P1140相似基因:https://www.luogu.com.cn/problem/P1140
思路:dp[i] [j]表示第一个基因的前i位和第二个基因的前j位的最大匹配,则可以从dp[i-1] [j],dp[i-1] [j-1], dp[i] [j-1]三种情况转移过来。只需要关注每次添加的字母是谁就可以了。
#include<bits/stdc++.h> using namespace std; const int M=1e2+50; struct Task{ int len1,len2,dp[M][M]; char s1[M],s2[M]; map<int,int> mp={{'A',1},{'C',2},{'G',3},{'T',4},{'-',5}}; int tr[6][6]={ {0,0,0,0,0,0}, {0,5,-1,-2,-1,-3}, {0,-1,5,-3,-2,-4}, {0,-2,-3,5,-2,-2}, {0,-1,-2,-2,5,-1}, {0,-3,-4,-2,-1,0}}; void init(){ scanf("%d%s%d%s",&len1,s1+1,&len2,s2+1); for(int i=1;i<=len1;++i) dp[i][0]=dp[i-1][0]+tr[mp[s1[i]]][mp['-']]; for(int i=1;i<=len2;++i) dp[0][i]=dp[0][i-1]+tr[mp[s2[i]]][mp['-']]; for(int i=1;i<=len1;++i) for(int j=1;j<=len2;++j) dp[i][j]=-1e9; } void run(){ init(); for(int i=1;i<=len1;++i) for(int j=1;j<=len2;++j) dp[i][j]=max(dp[i][j],dp[i-1][j]+tr[mp[s1[i]]][mp['-']]), dp[i][j]=max(dp[i][j],dp[i][j-1]+tr[mp[s2[j]]][mp['-']]), dp[i][j]=max(dp[i][j],dp[i-1][j-1]+tr[mp[s1[i]]][mp[s2[j]]]); printf("%d\n",dp[len1][len2]); } }t; int main(){ t.run(); return 0; }
数学
1.P2158:洛谷仪仗队
题解:首先可以只观察一半,对第二列,能看到1个,第三列看到2个,实际上就是(3,1)(3,2)这里面两个数互质的个数,所以其实就是phi的前缀和*2+1。
#include<bits/stdc++.h> using namespace std; const int M=1e5+20; #define LL long long int vis[M],prime[M],cnt; LL phi[M]; void get(int n){ phi[1]=1; for(int i=2;i<=n;i++){ if(!vis[i]) prime[++cnt]=i,phi[i]=i-1; for(int j=1;j<=cnt&&prime[j]*i<=n;j++){ vis[i*prime[j]]=1; if(i%prime[j]==0){ phi[i*prime[j]]=phi[i]*prime[j]; break; } phi[i*prime[j]]=phi[i]*(prime[j]-1); } } for(int i=1;i<=n;i++) phi[i]+=phi[i-1]; } int main(){ int n; scanf("%d",&n); get(n); if (n==1) printf("0\n"); else printf("%lld\n",phi[n-1]*2+1); return 0; }
2.P1582
题意:有n个瓶子,每个都有1L水,每次只能选择两个水相同的瓶子,合成一个,扔掉空瓶子。现在需要保留最多k个瓶子,问需要至少购买多少个新的有1L水的新瓶子?
思路:水瓶里的水的体积一定是2的幂,所以n瓶水最少需要的瓶子数,等于n的二进制拆分中1的个数。那么如何减少1的个数呢?答案是需要购买lowbit(n)个新瓶子,然后合成,进位,可能会减少1的数量。
#include<bits/stdc++.h> using namespace std; int get_num(int x){ int ans=0; for(int i=0;i<=31;++i) ans+=((x>>i)&1); return ans; } inline int lowbit(int x){return x&-x;} int main(){ int n,k; scanf("%d%d",&n,&k); int ans=0; while(get_num(n)>k) ans+=lowbit(n),n+=lowbit(n); printf("%d\n",ans); return 0; }
分块&&莫反
1.BZOJ1257:计算k%1+k%2+...+k%n的和。1e9。
思路:最简单的分块题目,将取模拆开即可。
\[
\Sigma_{i=1}^{n}k-\lfloor\frac{k}{i}\rfloor*i\\
n*k-\Sigma_{i=1}^{n}i*\lfloor\frac{k}{i}\rfloor
\]
这里有个小技巧(学来的:https://blog.csdn.net/qq_42886072/article/details/89408397),特判0和超过n的情况。
#include<bits/stdc++.h> using namespace std; struct Task{ long long ans,n,k; void init(){ scanf("%lld%lld",&n,&k); } void run(){ init(); for(int l=1,r;l<=n;l=r+1) r=(k/l?min(n,k/(k/l)):n),ans+=1LL*(l+r)*(r-l+1)/2*(k/l); printf("%lld\n",n*k-ans); } }t; int main(){ t.run(); return 0; }
2.BZOJ2956:求∑∑((n mod i)*(m mod j))其中1<=i<=n,1<=j<=m,i≠j。 mod19940417。
题解:直接两个分别求,然后相乘即可。注意要把i==j的情况减掉!!!
#include<bits/stdc++.h> using namespace std; #define LL long long const int P=19940417; struct Task{ int n,m; void init(){ scanf("%d%d",&n,&m); } inline LL sing(int n){return 1LL*n*(n+1)/2%P;} LL calc(int k,int n){//计算1-k,n/i的和 LL ans=0; for(int l=1,r;l<=k;l=r+1) r=(n/l?min(k,n/(n/l)):k),ans=(ans+(sing(r)-sing(l-1))%P*(n/l)%P)%P; return ans; } inline LL sqr(int n){return (__int128)n*(n+1)*(2*n+1)/6%P;} LL cald(int k,int n,int m){ LL ans=0; for(int l=1,r;l<=k;l=r+1) r=min(n/l?min(k,n/(n/l)):k,m/l?min(k,m/(m/l)):k),ans=(ans+(sqr(r)-sqr(l-1))%P*(n/l)%P*(m/l)%P)%P; return ans; } void run(){ init(); int k=min(n,m); printf("%lld\n",((1LL*n*n%P-calc(n,n)+P)%P*(1LL*m*m%P-calc(m,m)+P)%P-(1LL*k*n%P*m%P-m*calc(k,n)%P+P-n*calc(k,m)%P+P+cald(k,n,m))%P+P)%P); } }t; int main(){ t.run(); return 0; }
莫比乌斯反演
1.BZOJ1101:
#include<bits/stdc++.h> using namespace std; const int M=5e4+20; #define LL long long LL cnt,phi[M],mu[M],prime[M],vis[M]; void get(int n){ phi[1]=mu[1]=1; for(int i=2;i<=n;i++){ if(!vis[i]) prime[++cnt]=i,mu[i]=-1,phi[i]=i-1; for(int j=1;j<=cnt&&prime[j]*i<=n;j++){ vis[i*prime[j]]=1; if(i%prime[j]==0){ phi[i*prime[j]]=phi[i]*prime[j]; break; } mu[i*prime[j]]=-mu[i],phi[i*prime[j]]=phi[i]*(prime[j]-1); } } for(int i=1;i<=n;i++) mu[i]+=mu[i-1],phi[i]+=phi[i-1]; } struct Task{ int d,a,b; void init(){ scanf("%d%d%d",&a,&b,&d); } LL cald(int k,int n,int m){ LL ans=0; for(int l=1,r;l<=k;l=r+1) r=min(n/l?min(k,n/(n/l)):k,m/l?min(k,m/(m/l)):k),ans+=(mu[r]-mu[l-1])*(n/l)*(m/l); return ans; } void run(){ init(); printf("%lld\n",cald(min(a/d,b/d),a/d,b/d)); } }t; int main(){ get(5e4+2); int T; scanf("%d",&T); for(int i=1;i<=T;++i) t.run(); return 0; }
2.BZOJ2301:
思路:二维前缀和思想,ans=cgcd(b,d,k)-cgcd(a-1,d,k)-cgcd(b,c-1,k)+cgcd(a-1,c-1,k)
#include<bits/stdc++.h> using namespace std; const int M=5e4+20; #define LL long long int cnt,mu[M],prime[M],vis[M]; void get(int n){ mu[1]=1; for(int i=2;i<=n;i++){ if(!vis[i]) prime[++cnt]=i,mu[i]=-1; for(int j=1;j<=cnt&&prime[j]*i<=n;j++){ vis[i*prime[j]]=1; if(i%prime[j]==0) break; mu[i*prime[j]]=-mu[i]; } } for(int i=1;i<=n;i++) mu[i]+=mu[i-1]; } struct Task{ int a,b,c,d,k; void init(){ scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); } LL cald(int k,int n,int m){ LL ans=0; for(int l=1,r;l<=k;l=r+1) r=min(n/l?min(k,n/(n/l)):k,m/l?min(k,m/(m/l)):k),ans+=1LL*(mu[r]-mu[l-1])*(n/l)*(m/l); return ans; } inline LL cgcd(int a,int b,int d){return cald(min(a/d,b/d),a/d,b/d);}//计算i:1-a,j:1-b,gcd=d的数的个数 void run(){ init(); printf("%lld\n",cgcd(b,d,k)-cgcd(a-1,d,k)-cgcd(b,c-1,k)+cgcd(a-1,c-1,k)); } }t; int main(){ get(5e4+2); int T; scanf("%d",&T); for(int i=1;i<=T;++i) t.run(); return 0; }
3.BZOJ2820:
#include<bits/stdc++.h> using namespace std; const int M=1e7+20; #define LL long long int cnt,mu[M],prime[M],vis[M]; LL f[M]; void get(int n){ mu[1]=1; for(int i=2;i<=n;i++){ if(!vis[i]) prime[++cnt]=i,mu[i]=-1; for(int j=1;j<=cnt&&prime[j]*i<=n;j++){ vis[i*prime[j]]=1; if(i%prime[j]==0) break; mu[i*prime[j]]=-mu[i]; } } for(int i=1;i<=cnt;++i) for(int j=1;j*prime[i]<=n;++j) f[j*prime[i]]+=mu[j]; for(int i=1;i<=n;++i) f[i]+=f[i-1]; } struct Task{ int n,m; void init(){ scanf("%d%d",&n,&m); } LL cald(int k,int n,int m){ LL ans=0; for(int l=1,r;l<=k;l=r+1) r=min(n/l?min(k,n/(n/l)):k,m/l?min(k,m/(m/l)):k),ans+=(f[r]-f[l-1])*(n/l)*(m/l); return ans; } void run(){ init(); printf("%lld\n",cald(min(n,m),n,m)); } }t; int main(){ get(1e7+2); int T; scanf("%d",&T); for(int i=1;i<=T;++i) t.run(); return 0; }
4.P2568:
很不理解,我预处理1e7会挂,但预处理n就不挂了,难道又是数据水?根本没有1e7的数据?
#include<bits/stdc++.h> using namespace std; const int M=1e7+20; #define LL long long int cnt,mu[M],prime[M],vis[M]; int f[M]; void get(int n){ mu[1]=1; for(int i=2;i<=n;i++){ if(!vis[i]) prime[++cnt]=i,mu[i]=-1; for(int j=1;j<=cnt&&prime[j]*i<=n;j++){ vis[i*prime[j]]=1; if(i%prime[j]==0) break; mu[i*prime[j]]=-mu[i]; } } for(int i=1;i<=cnt;++i) for(int j=1;j*prime[i]<=n;++j) f[j*prime[i]]+=mu[j]; for(int i=1;i<=n;++i) f[i]+=f[i-1]; } struct Task{ int n; void init(){ scanf("%d",&n); } LL cald(int k,int n,int m){ LL ans=0; for(int l=1,r;l<=k;l=r+1) r=min(n/l?min(k,n/(n/l)):k,m/l?min(k,m/(m/l)):k),ans+=1LL*(f[r]-f[l-1])*(n/l)*(m/l); return ans; } void run(){ init(); get(n); printf("%lld\n",cald(n,n,n)); } }t; int main(){ t.run(); return 0; }
来源:https://www.cnblogs.com/diorvh/p/12099844.html