1.最大乘积
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
const int N=12;
bool st[N];
int s[N];
vector<int>num;
long long maxans=0;
int divide(int l,int r)
{
int t=0;
for(int i=l; i<r; i++)
{
t*=10;
t+=num[i];
}
return t;
}
bool judge(int x,int y)
{
memset(s,0,sizeof s);
long long k=(long long)x*y;
long long sum=k;
int w=0;
while(sum)
{
s[sum%10]++;
sum/=10;
w++;
}
if(w!=9)
return false;
for(int i=1; i<=9; i++)
{
if(s[i]!=1)
return false;
}
maxans=max(maxans,k);
return true;
}
void dfs(int u)
{
if(u==9)
{
for(int i=1; i<9; i++)
{
int x=divide(0,i);
int y=divide(i,9);
judge(x,y);
}
return;
}
for(int i=1; i<=9; i++)
{
if(!st[i])
{
st[i]=true;
num.push_back(i);
dfs(u+1);
num.pop_back();
st[i]=false;
}
}
}
int main()
{
dfs(0);
printf("%lld",maxans);
return 0;
}
2.阶乘约数
任意一个正整数 X 都可以表示成若干个质数乘积的形式,即 X = p1α1 ∗ p2α2 …… ∗ pkαk
约数个数 = (a1 + 1)(a2 + 1)……(ak + 1)
#include <iostream>
#include <unordered_map>
using namespace std;
unordered_map<int,int>h;
int main()
{
for(int i=2;i<=100;i++){
int t=i;
for(int j=2;j<=t/j;j++){
while(t%j==0){
h[j]++;
t/=j;
}
}
//注意可能没有除尽
if(t>1)h[t]++;
}
long long ans=1;
for(int i=2;i<99;i++){
if(h[i]>0)ans*=(h[i]+1);
}
printf("%lld",ans);
return 0;
}
3.含 2 天数
#include <iostream>
using namespace std;
int month[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
bool isdate(int date){
int yyyy=date/10000;
int mm=date/100%100;
int dd=date%100;
if(mm>12||mm<=0)return false;
if(yyyy%400==0||(yyyy%4==0&&yyyy%100!=0)){
month[2]=29;
}else{
month[2]=28;
}
if(dd<=month[mm]&&dd>=1)return true;
return false;
}
bool check(int date){
while(date){
if(date%10==2)return true;
date/=10;
}
return false;
}
int main()
{
int ans=0;
for(int i=19000101;i<=99991231;i++){
if(isdate(i)){
if(check(i)){
ans++;
}
}
}
printf("%d",ans);
return 0;
}
4.k倍区间
法一:前缀和
时间复杂度O(n2 )
得分28 其余样例超时
#include <iostream>
using namespace std;
const int N=1e5+100;
int num[N];
int s[N];
int main(){
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&num[i]);
s[i]=s[i-1]+num[i];
}
long long ans=0;
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
if((s[j]-s[i-1])%k==0){
ans++;
}
}
}
printf("%lld",ans);
return 0;
}
法二:优化
s[j]-s[i-1])%k==0 即s[j]与s[i-1]的余数相同
利用cnt[N]统计余数相同的数的个数,即区间(l,r]中余数相同的数的个数
另外要注意一点是,假如某一段数A1…Ai,不需要减去区间,它本身就是一个K倍区间,但cnt[0]保存的是i之前余数为0的前缀和的个数,这个区间本身没有被算进去,所以初始状态下,cnt[0]应该赋值为1
时间复杂度:O(n3 )->前缀和O(n2 )->存余数O(n)
#include <iostream>
using namespace std;
const int N=1e5+100;
long long s[N];
long long cnt[N];
int main(){
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&s[i]);
s[i]+=s[i-1];
}
long long ans=0;
cnt[0]=1;
for(int i=1;i<=n;i++){
ans+=cnt[s[i]%k];
cnt[s[i]%k]++;
}
printf("%lld",ans);
return 0;
}