hdu4704 Sum
题面:
思路:
一开始没看懂题。。。
其实就是把n拆成若干正整数之和,计算一共有多少种拆法。
而且因为每个X[i]是有编号i的,所以a+b和b+a算两种。
把n看成n个1排在一排,然后放隔板去分割,一共n-1个空位,每个空位有放和不放两种选择,因此总的方案数是2n-1
然后看到n非常大,已经是数字串了,考虑降幂。
因为1e9+7是质数,根据费马小定理,把幂次(n-1)对1e9+6取模即可降幂。
之后就变成一道快速幂简单题了。
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int ppow(int a,int b,int mod){
a%=mod;
int ans=1;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
const int maxm=1e5+5;
const int mod=1e9+7;
char s[maxm];
signed main(){
while(scanf("%s",s+1)!=EOF){
int n=strlen(s+1);
int p=0;
for(int i=1;i<=n;i++){
p=(p*10+s[i]-'0')%(mod-1);
}
p=(p-1+mod-1)%(mod-1);
cout<<ppow(2,p,mod)<<endl;
}
return 0;
}
hdu5750 Dertouzos
题意:
给n和d,问有多少个比n小的正整数,其不等于自身的最大约数为d。
思路:
一开始以为是水题,这不就是统计1-(n-1)中有多少个(d乘prime)吗
然而还是太年轻了,这题还有一个细节:
如果d是prime的倍数,那么就可以把d质因子分解,(d乘prime)可以提出来一个最小的质因子p,(d乘prime)=(p乘dd)
其中dd是新的最大因子,这样就不满足最大因子为d了,所以循环到d%prime==0之后就要跳出去。
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=1e5+5;
bool notprime[maxm];
int prime[maxm],cnt;
void init(){
for(int i=2;i<maxm;i++){
if(!notprime[i]){
prime[cnt++]=i;
}
for(int j=0;j<cnt;j++){
if(1LL*prime[j]*i>=maxm)break;
notprime[prime[j]*i]=1;
if(i%prime[j]==0)break;
}
}
}
signed main(){
init();
int T;
cin>>T;
while(T--){
int n,d;
scanf("%d%d",&n,&d);
int ans=0;
for(int i=0;i<cnt;i++){
if(prime[i]>d)break;
if(1LL*prime[i]*d>=n)break;
ans++;
if(d%prime[i]==0)break;//如果能整除d,那么d就可以被分解,形成d'(d'>d)
}
printf("%d\n",ans);
}
return 0;
}
CodeForces484 B.Maximum Value
题意:
给长度为n的数组a
要求计算a(i)%a(j)的最大值,其中a(i)>=a(j)
数据范围:n<=2e5,a(i)<=1e6
思路:
首先暴力O(n2)枚举肯定超时。
设a(i)%a(j)=x
则x=a(i)-a(j)k,由取余性质可知,a(j)k<=a(i)<=a(j)(k+1)
因为题目数据最大1e6,所以可以直接枚举a(j)和倍数(k+1),在数组中二分出小于a(j)(k+1)的最大的数a(t)
因为显然a(j)k<=a(i)<=a(j)(k+1)范围中的a(i)越大,答案x越大。
如果a(j)(k+1)-a(t)<a(j)说明a(j)k<=a(t)<=a(j)(k+1),即合法,用a(t)%a(j)更新答案。
当a(j)k>1e6的时候停止枚举k。
ps:
因为要二分,所以数组需要先排序
如果数组中由重复的a(j),只计算一次就行了。
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=1e6+5;
int a[maxm];
signed main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
sort(a+1,a+1+n);
int ans=0;
for(int j=1;j<=n;j++){//枚举模数a[j];
if(a[j]==a[j-1])continue;
for(int k=1;;k++){//枚举倍数
int now=(k+1)*a[j];
int l=1,r=n;
int pos=0;
while(l<=r){
int mid=(l+r)/2;
if(a[mid]<now)pos=mid,l=mid+1;
else r=mid-1;
}
if(!pos)break;
if(now-a[pos]<a[j]){
ans=max(ans,a[pos]%a[j]);
}
if(now>1e6)break;
}
}
printf("%d\n",ans);
return 0;
}
CodeForces1247 D. Power Products
题意:
给长度为n的数组a,和一个整数k
问有多少对1<=i<j<=n
满足a(i)*a(j)=xk,其中x为任意数
数据范围:n<=2e5,k<=100,a(i)<=1e5
思路:
两数的乘积是x的k次方,那么他们乘积的每种质因子的幂次都是k的倍数,
用vector+pair记录每个数的质因子以及次数,找出要匹配的质因子以及次数,用map记录和查询即可
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=1e5+5;
map<vector<pair<int,int> >,int>mark;
int a[maxm];
int n,k;
int ans;
signed main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
vector<pair<int,int> >now;
vector<pair<int,int> >need;
for(int j=2;j*j<=a[i];j++){
if(a[i]%j==0){
int cnt=0;
while(a[i]%j==0){
a[i]/=j;
cnt++;
}
cnt%=k;//对k取模
if(cnt){//如果为0就不用加进去了
now.push_back({j,cnt});
}
}
}
if(a[i]!=1){
now.push_back({a[i],1});
}
for(auto i:now){
need.push_back({i.first,k-i.second});
}
ans+=mark[need];
mark[now]++;
}
cout<<ans<<endl;
return 0;
}
AtCoder5361(ABC158E) Divisible Substring
题意:
给一个长度为n的数字串和一个质数p
问有多少个子串模p等于0
思路:
当p为2和5的时候,所有10的倍数模p都是0,例如(100a+10b+c)%p等价于c%p,因此只判断最后一位是否模p等于0即可。
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=5e5+5;
map<int,int>mark;
char s[maxm];
int n,p;
signed main(){
cin>>n>>p;
scanf("%s",s+1);
int ans=0;
if(p==2||p==5){
for(int i=1;i<=n;i++){
if((s[i]-'0')%p==0){
ans+=i;
}
}
}else{
int base=1;
int sum=0;
mark[0]=1;
for(int i=n;i>=1;i--){
sum=(sum+(s[i]-'0')*base)%p;
ans+=mark[sum];
mark[sum]++;
base=base*10%p;
}
}
cout<<ans<<endl;
return 0;
}