Diorvh

导航

【日记】12.25

今天写了一天的题,并没有复习。

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;
}

posted on 2019-12-26 00:32  diorvh  阅读(114)  评论(0编辑  收藏  举报