蒟蒻勉强打了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;
}
 京公网安备 11010502036488号
京公网安备 11010502036488号