蒟蒻勉强打了3题,第4题开始不会了。。
这里放了前4题的代码和题解。
A 小G的sum
显然对于任意一个数i,最大的约数为i,最小的约数为1.
因此答案就是n+(1+2+3...n)=n+(1+n)*n/2
注意开long long
代码:
#include<bits/stdc++.h> using namespace std; int main() { long long n; cin>>n; long long ans; ans=n+(1+n)*n/2; cout<<ans<<endl; }
B 小G的GCD
根据f(x)的定义我们可以知道,f(x)=(1+2+3+...int(x/k))*k
因此我们枚举f(i)求和就可以了。
代码:#include<bits/stdc++.h> using namespace std; int n,k; long long solve(int x){ // if(x<k)return 0; int t=x/k; return 1ll*(1+t)*t/2*k; } int main() { long long ans=0; cin>>n>>k; for(int i=1;i<=n;i++){ ans+=solve(i); } cout<<ans<<endl; return 0; }
C 小G的约数
首先G(n)我们可以暴力计算,然后发现要算G(G(n))的话,会超时的。
再回过来看f(n)的定义是f(n)=n的约数和。
G(n)=f(1)+f(2)+...f(n)
可以发现G(n)其实的是n个1+n/2个2+n/3个3+...n/n个n
即G(n)=n1+int(n/2)2+int(n/3)3+...int(n/i)i+...int(n/n)*n
可以发现这其实是一个整除分块,对于k=int(n/i)我们可以分出其中的一个连续块,令区间[l,r]中的任意一个i,使得int(n/l)=int(n/r)=int(n/i)。
而这个r=n/(n/l)
这里的复杂度为O(logn)
那么我们直接计算出G(n)以后,再利用整除分块计算G(G(n))就可以了。
代码:#include<bits/stdc++.h> using namespace std; int n; long long g; int main() { cin>>n; for(int i=1;i<=n;i++){ g+=n/i*i; } long long ans=0; for(long long l=1,r;l<=g;l=r+1){ r=g/(g/l); ans+=(g/l)*(l+r)*(r-l+1)/2; } cout<<ans<<endl; return 0; }
事实上,在做本题之前我只做过一题整除分块,对这玩意也是一知半解。我在比赛中,想到的是上面的那个式子可以转化成n*n-(n%1+n%2+n%3+...n%n)
因此我们只要求后面的那个式子就好了。
首先可以发现对于i>n/2的情况,是一个等差数列。即在(n/2,n]区间内是等差数列,公差为1。
同理可以发现,(n/3,n/2]是公差为2的等差数列。
因此我们可以枚举这些区间,到什么时候结束呢?
我们可以计算从以n/sqrt(n)开始的区间,到最后的(n/2,n]的区间利用等差数列公式求和,sqrt(n)之前的我们可以暴力计算。
代码:
#include<bits/stdc++.h> using namespace std; int n; long long g; int main() { cin>>n; for(int i=1;i<=n;i++){ g+=n/i*i; } long long ans=g*g; int t=sqrt(g); for(int i=1;i<=g/t;i++){ ans=ans-g%i; } for(int i=2;i<=t;i++){ long long len=g/(i-1)-g/i; ans=ans-(g%(g/(i-1))+g%(g/i+1))*len/2; } cout<<ans<<endl; return 0; }
D 小G的LY数对
这题暴力也没想到。。
看了一下别人的题解,也是利用暴力+哈希过的。
之前没有用过unorder_map
基本思路就是先把a数组里的数放到unorder_map中,然后暴力枚举b数组中的数并且枚举(i,j)两个位置修改b数组的数,修改完以后看一下map中这个数字有多少个放到答案里面进行统计。
这样做估计的复杂度是O(30^2*n),加上map的巨大常数,直接T了。
参考了一下,有人用bitset先判数字是否在a中出现,然后再去看有多少个答案进行统计。
算是卡过去了。
先把代码贴一下,明天有时间写一下哈希的代码:#include<bits/stdc++.h> using namespace std; int n,m,b[300040],c[30]; unordered_map<int,int>mp; bitset< 1<<30 >v; inline int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') w = -1; ch = getchar();} while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar(); return s * w; } int main() { mp.reserve(300005); n=read();m=read(); int i,j,k,x; for(i=1;i<=n;i++){ x=read(); v[x]=true; mp[x]++; } for(i=1;i<=m;i++){ b[i]=read(); } long long ans=0; int tmp; for(i=0;i<30;i++){ for(j=i+1;j<30;j++){ for(k=1;k<=m;k++){ tmp=b[k]; tmp^=(1<<i); tmp^=(1<<j); if(v[tmp]) ans+=mp[tmp]; } } } cout<<ans<<endl; return 0; }
今天把哈希表的代码补上。速度快很多
#include<bits/stdc++.h> using namespace std; const int mod=1000007; int n,m,b[300040]; inline int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') w = -1; ch = getchar();} while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar(); return s * w; } struct node{ int to,next,w; }p[300050]; int tot,head[2000050]; void add(int x){ int a=x%mod; for(int i=head[a];~i;i=p[i].next){ if(p[i].to==x){ p[i].w++; return; } } p[tot].to=x;p[tot].w++;p[tot].next=head[a];head[a]=tot++; } int query(int x){ int a=x%mod; for(int i=head[a];~i;i=p[i].next){ if(p[i].to==x){ return p[i].w; } } return 0; } int main() { memset(head,-1,sizeof(head)); n=read();m=read(); int i,j,k,x; for(i=1;i<=n;i++){ x=read(); add(x); } for(i=1;i<=m;i++){ b[i]=read(); } long long ans=0; for(int i=0;i<30;i++){ for(int j=i+1;j<30;j++){ for(int k=1;k<=m;k++){ int tmp=b[k]; tmp^=(1<<i); tmp^=(1<<j); ans+=query(tmp); } } } cout<<ans<<endl; return 0; }