◇题目传送门◆
给定三个数字 A , B , C A,B,C A,B,C,要求使用这三个数字组成一个两位数及一个一位数,使得他们的和最大
似乎没有什么可以讲的,直接给出代码吧。
#include
#include
using namespace std;
int main() {
#ifdef LOACL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int a[3];
scanf("%d %d %d",&a[0],&a[1],&a[2]);
sort(a,a+3);
printf("%d\n",a[2]*10+a[1]+a[0]);
return 0;
}
◇题目传送门◆
给定两个数 N , M N,M N,M和数轴上的两个点 X , Y X,Y X,Y与 N N N个点 x 1 , x 2 , x 3 , … , x N x_1,x_2,x_3,\ldots,x_N x1,x2,x3,…,xN和 M M M个点 y 1 , y 2 , y 3 , … , y M y_1,y_2,y_3,\ldots,y_M y1,y2,y3,…,yM,要求找出一个点 Z Z Z,使得它满足以下条件:
我们记 x 0 = X , y 0 = Y x_0=X,y_0=Y x0=X,y0=Y,仔细分析题目可以发现,当存在 max { x 0 , x 1 , x 2 , … , x N } < min { y 0 , y 1 , y 2 … , y M } \max\{x_0,x_1,x_2,\ldots,x_N\}<\min\{y_0,y_1,y_2\ldots,y_M\} max{x0,x1,x2,…,xN}<min{y0,y1,y2…,yM}时,就会有 Z Z Z存在。
所以直接给出代码:
#include
#include
using namespace std;
const int Maxn=100;
int N,M,X,Y;
int A[Maxn+5],B[Maxn+5];
int main() {
#ifdef LOACL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
scanf("%d %d %d %d",&N,&M,&A[0],&B[0]);
for(int i=1;i<=N;i++)
scanf("%d",&A[i]);
for(int i=1;i<=M;i++)
scanf("%d",&B[i]);
int maxa=*max_element(A,A+N+1);
int minb=*min_element(B,B+M+1);
if(maxa<minb)
puts("No War");
else puts("War");
return 0;
}
◇题目传送门◆
给定两个串 S , T S,T S,T,保证两串长度相等。要求使用如下操作,使得 S , T S,T S,T相同:
操作:从26个字母中选择两个字母 c 1 , c 2 c_1,c_2 c1,c2,在 S S S中,将所有的 c 1 c_1 c1替换为 c 2 c_2 c2,所有的 c 2 c_2 c2替换为 c 1 c_1 c1。
不难发现在串 S S S中,每个字母和串 T T T中的每个字母是有一一对应的关系。所以我们考虑在串 S S S中是否满足这个对应关系,在串 T T T中是否满足对应关系。想到这个即可过掉此题。
#include
#include
#include
#include
using namespace std;
const int Maxn=2*1e5;
char s[Maxn+5],t[Maxn+5];
int c[256+5];
int main() {
#ifdef LOACL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
scanf("%s %s",s,t);
int len=strlen(s);
memset(c,-1,sizeof c);
set<char> cnt;
for(int i=0;i<len;i++)
cnt.insert(s[i]);
for(int i=0;i<len;i++) {
if(c[t[i]]!=-1&&c[t[i]]!=s[i]) {
if(t[i]==s[i]&&cnt.size()<26)
continue;
puts("No");
return 0;
}
c[t[i]]=s[i];
}
memset(c,-1,sizeof c);
for(int i=0;i<len;i++) {
if(c[s[i]]!=-1&&c[s[i]]!=t[i]) {
if(t[i]==s[i]&&cnt.size()<26)
continue;
puts("No");
return 0;
}
c[s[i]]=t[i];
}
puts("Yes");
return 0;
}
◇题目传送门◆
给定两个数 N , M N,M N,M,要求找出 N N N个数,使得这 N N N个数的乘积等于 M M M。输出方案数模 1 0 9 + 7 10^9+7 109+7。
仔细分析可发现,这 N N N个数要么是 1 1 1,要么就是 N N N的质因数的乘积。
很自然的就扯到了唯一分解和组合数学上去。
记 M = p 1 a 1 p 2 a 2 ⋯ p m a m M=p_1^{a_1}p_2^{a_2}\cdots p_m^{a_m} M=p1a1p2a2⋯pmam,其中 p 1 , p 2 , … , p m p_1,p_2,\ldots,p_m p1,p2,…,pm为质数。
当我们将 a i a_i ai个质数 p i p_i pi(其中 1 ≤ i ≤ m 1\le i\le m 1≤i≤m)加入到 N N N个数中,就相当于将 N + a i − 1 N+a_i-1 N+ai−1个数分成 N − 1 N-1 N−1块的组合数。
所以我们就可以得到:此时的方案数为 C ( N + a i − 1 , N − 1 ) C(N+a_i-1,N-1) C(N+ai−1,N−1)。而由于在两个方案之间,有一个数不同即被视为不同,所以,我们只需要将所有的方案数乘上即可。
即方案数为 ∏ i = 1 m C ( N + a i − 1 , N − 1 ) \prod_{i=1}^{m}C(N+a_i-1,N-1) i=1∏mC(N+ai−1,N−1)
注意此时若 M ≠ 1 M\ne1 M̸=1时,答案是还需乘上 N N N的。(请读者自己思考)
特别注意:由于这道题要求取模,而组合数计算需要除法,所以我们必须使用逆元!不知道逆元的读者请点这里
接下来分析时间复杂度:
预处理阶乘和逆元需要 O ( N log 2 M o d ) O(N\log_2Mod) O(Nlog2Mod)。
唯一分解所需要的时间为 O ( M ) O(\sqrt{M}) O(M)。
计算答案需要 O ( 1 ) O(1) O(1)。
又由于 N N N远小于 M M M,所以,总时间复杂度为 O ( M ) O(\sqrt{M}) O(M)。
#include
#include
#include
using namespace std;
typedef long long ll;
const int Mod=1e9+7;
const int Maxn=1.5*1e5;
int N,M;
ll PowMod(ll a,int b) {
ll ret=1;
while(b) {
if(b&1)ret=ret*a%Mod;
a=a*a%Mod;
b>>=1;
}
return ret;
}
ll f[Maxn+5];
ll inv[Maxn+5];
void Prepare() {
f[0]=1;
for(int i=1;i<=Maxn;i++)
f[i]=f[i-1]*i%Mod;
inv[0]=1;
inv[Maxn]=PowMod(f[Maxn],Mod-2);
for(int i=Maxn-1;i>0;i--)
inv[i]=inv[i+1]*(i+1)%Mod;
}
ll F(int a,int b) {
return f[a+b-1]*inv[a-1]%Mod*inv[b]%Mod;
}//C(a+b-1,a-1)
int main() {
#ifdef LOACL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
scanf("%d %d",&N,&M);
Prepare();
int lim=sqrt(M);
ll ans=1;
for(int i=2;i<=lim;i++)
if(M%i==0) {
int cnt=0;
while(M%i==0)
M/=i,cnt++;
ans=ans*F(N,cnt)%Mod;
}
if(M!=1)ans=ans*N%Mod;
printf("%lld",ans);
return 0;
}