今天写了一天的题,并没有复习。
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
",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
");
else
printf("%lld
",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
",ans);
return 0;
}
分块&&莫反
1.BZOJ1257:计算k%1+k%2+...+k%n的和。1e9。
思路:最简单的分块题目,将取模拆开即可。
这里有个小技巧(学来的: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*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
",((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
",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
",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
",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
",cald(n,n,n));
}
}t;
int main(){
t.run();
return 0;
}