A題題意:有一個序列a1...an,您需要回答m個詢問,每個詢問給一個b,使刪除儘量少的數使得任意時刻前綴和都>=b(m<=10^4,n<=10^3)
由於FLOJ跑的太快了,導致沒有數據可以卡掉O(mnlogn)
我倒是寫了一個整體二分求ans[i]表示需要刪i個數時的最小b,O(nlogn*30+mlogn)?
正解:dp[i][j]表示a1..ai中刪j個數時的最小前綴和,詢問時二分,O(mlogn+n^2)
兩道題組合即視感。。。
對於Part I:求一個f(i),它其實就是一個假phi,只是在設初值時f[p]=(n%p==0?p:p-1)(p爲質數)再O(m)求和
對於Part II:搞一個f(k,p)爲答案,則
它一定會在O(log n)的時間中得到p<=1。。。沒了
C題題意:求 其中f(0)=0,f(1)=1,f(n)=f(n-1)+f(n-2)(n>=2),(an<=1000000,n<=50000)
首先您需要知道一個定理:f(gcd(x,y))=gcd(f(x),f(y))(證明略。。。)
這樣,我們就可以直接考慮下標間的關係了
然後有這樣一個容斥式子:於是我們就可以考慮求每個i的貢獻
於是:設F(i)爲i|gcd的a的貢獻,則F(i)=C(1,F(i))-C(2,F(i))+C(3,F(i))...=[F(i)!=0]
設G(i)爲i=gcd的a的貢獻,G(i)=F(i)-G(2i)-G(3i)-...
然後用快速冪累乘即可,O(ClogC)(C<=1e6)
AC Code:
B題:
#include<bits/stdc++.h>
#define maxn 10001000
using namespace std;
typedef long long ll;
int phi[maxn],m,n,p,phi2[maxn],pri[maxn],psz,vis[maxn];
int qpow(int a,int b,int p){
int ans=1,tmp=a;
for(;b;b>>=1,tmp=1ll*tmp*tmp%p)
if(b&1)ans=1ll*ans*tmp%p;
return ans;
}
int find(int k,int p){
// printf("[%d,%d]\n",k,p);
if(k==0)return 1;
if(p==1)return 0;
return qpow(k,find(k,phi[p])+phi[p],p);
}
int main(){
scanf("%d%d%d",&m,&n,&p);
phi[1]=phi2[1]=1;
int lim=max(max(m,n),p);
for(int i=2;i<=lim;i++){
if(!vis[i]){pri[psz++]=i;phi[i]=i-1;phi2[i]=(m%i==0?i:i-1);}
for(int j=0;j<psz&&i*pri[j]<=lim;++j){
vis[i*pri[j]]=true;
if(i%pri[j]){
phi[i*pri[j]]=phi[i]*phi[pri[j]];
phi2[i*pri[j]]=phi2[i]*phi2[pri[j]];
} else {
phi[i*pri[j]]=phi[i]*pri[j];
phi2[i*pri[j]]=phi2[i]*pri[j];
}
}
}
ll k=0;
for(int i=1;i<=n;++i)k=(k+1ll*phi2[i]*phi[m])%1000000007;
// printf("[%d]",k);
printf("%d",find(k,p));
}
C題:
#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;
int f[1000100],F[1000100],G[1000100],a[50100],n,ans=1;
int qpow(int a,int b,int p){
int tmp=a,ans=1;
for(;b;b>>=1,tmp=1ll*tmp*tmp%p)
if(b&1)ans=1ll*ans*tmp%p;
return ans;
}
int main(){
f[0]=0,f[1]=1;
for(int i=2;i<=1000000;++i)f[i]=(f[i-1]+f[i-2])%mod;
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%d",&a[i]);
for(int i=1;i<=n;++i)
for(int j=1;j*j<=a[i];++j)if(a[i]%j==0){
F[j]++;if(j*j!=a[i])F[a[i]/j]++;
}
// for(int i=1;i<=n;++i)ans=1ll*ans*f[a[i]]%mod;
// printf("[%d]",ans);
for(int i=1000000;i>=1;--i){
G[i]=(F[i]!=0);
for(int j=2*i;j<=1000000;j+=i)
G[i]-=G[j];
// if(G[i])printf("[%d:%d]",f[i],G[i]);
if(G[i]<0)ans=1ll*ans*qpow(f[i],mod-1+G[i],mod)%mod;
else if(G[i])ans=1ll*ans*qpow(f[i],G[i],mod)%mod;
}
printf("%d",ans);
}