Coprime Integers
题意: x ∈ [ l 1 , r 1 ] , y ∈ [ l 2 , r 2 ] x\in[l1,r1],y\in[l2,r2] x∈[l1,r1],y∈[l2,r2],求gcd(x,y)=1的对数
解析:
莫比乌斯函数,定义g(x)表示gcd=x的对数,定义 f ( x ) = ∑ g ( i x ) f(x)=\sum g(ix) f(x)=∑g(ix),那么 g ( x ) = ∑ μ ( i ) f ( i x ) g(x)=\sum \mu(i)f(ix) g(x)=∑μ(i)f(ix)。 f ( x ) f(x) f(x)就表示 g c d = i x gcd=ix gcd=ix的方案数,直接算即可。
#include<bits/stdc++.h>
using namespace std;
#define D long long
#define F double
#define mmm(a,b) memset(a,b,sizeof(a))
D read(){ D ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
const int N=10000000;
const F pi=acos(-1);
D n,m,_n,_m,p=1e9+7,mi;
D f[N+9],mu[N+9];
D pri[664600],now;
bool vis[N+9];
void init(){
mmm(vis,0);mi=min(m,n);now=0;
for(D i=1;i<=mi;i++){
f[i]=((n/i)-(_n-1)/i)*((m/i)-(_m-1)/i);
}
mu[1]=1;
for(int i=2;i<=N;i++){
if(!vis[i]){
pri[++now]=i;
mu[i]=-1;
}
for(int j=1;j<=now&&i*pri[j]<=N;j++){
vis[i*pri[j]]=true;
if(i%pri[j])mu[i*pri[j]]=-mu[i];//出现新的素数 mu=-mu
else{
mu[i*pri[j]]=0; //出现相同素数
break;
}
}
}
}
int main(){
_n=read(),n=read(),_m=read(),m=read();
init();
D ans=0;
for(int i=1;i<=mi;i++)
ans+=f[i]*mu[i];
printf("%lld\n",ans);
}
Contest Setting
题意: 有n个数,选出x个不同的数的方案数
解析:
先统计每一种数出现的次数,用dp处理到第i种数,已经选j种的方案数。 d p [ i ] [ j ] = ( d p [ i ] [ j ] + d p [ i − 1 ] [ j − 1 ] ∗ a [ i ] + d p [ i − 1 ] [ j ] ) dp[i][j]=(dp[i][j]+dp[i-1][j-1]*a[i]+dp[i-1][j]) dp[i][j]=(dp[i][j]+dp[i−1][j−1]∗a[i]+dp[i−1][j])。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(register int i=a;i<=b;i++)
#define repp(i,a,b) for(register int i=a;i>=b;i--)
#define mmm(p) memset(p,0,sizeof p)
#define pill pair<int,int>
#define debug(i) printf("#%d\n",i)
#define D long long
typedef long long LL;
int read(){ int ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
map<LL,LL>vis;
LL a[1009],ct;
LL dp[1009][1009];
int main(){
int n=read(),k=read();
rep(i,1,n){
LL tmp=read();
vis[tmp]++;
}
for(map<LL,LL>::iterator it=vis.begin();it!=vis.end();it++){
a[++ct]=(*it).second;
}
rep(i,0,1001)dp[i][0]=1;
rep(i,1,ct){
rep(j,1,k){
dp[i][j]=(dp[i][j]+dp[i-1][j-1]*a[i]+dp[i-1][j])%mod;
}
}
printf("%lld\n",dp[ct][k]);
}
Count The Bits
题意: n和k,问 0 到 2 k − 1 0到2^{k}-1 0到2k−1中的n的倍数在二进制下的1的个数和。
解析:
以为是个数学题。。。从第k位往下搜,每一位填1或者0。维护一个模n的余数和已有的1的个数,到第一位余数为0说明可以整除。记忆化搜索加速。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(register int i=a;i<=b;i++)
#define repp(i,a,b) for(register int i=a;i>=b;i--)
#define mmm(p) memset(p,0,sizeof p)
#define pill pair<int,int>
#define debug(i) printf("#%d\n",i)
#define D long long
#define F double
typedef long long LL;
LL read(){ LL ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
const int mod= 1000000009;
int n,k;
int vis[131][1009][131];
int dfs(int pos,int have,int ct){
if(pos==1){
if(have==0)return vis[pos][have][ct]=ct;
return vis[pos][have][ct]=0;
}
int ans=0;
int to=have*2%n;
if(vis[pos-1][to][ct]>=0){
ans+=vis[pos-1][to][ct];
}
else {
ans+=dfs(pos-1,to,ct);
}
to=(have*2+1)%n;
if(vis[pos-1][to][ct+1]>=0){
ans=(ans+vis[pos-1][to][ct+1])%mod;
}
else{
ans=(ans+dfs(pos-1,to,ct+1))%mod;
}
return vis[pos][have][ct]=ans;
}
int main(){
memset(vis,-1,sizeof(vis));
n=read(),k=read();
int ans=dfs(k+1,0,0);
printf("%d\n",ans);
}