[NOIP模拟赛 - 20181012]a,b

题面:https://files.cnblogs.com/files/ErkkiErkko/statement3.pdf

T1 a:三指针法?

分析:

枚举行的组合,三个指针分别表示左边界,右边界的min,右边界的max,扫一遍即可。
附上自己的90pts代码(没加特判)。

代码:

由于某些原因,代码丢失。

T2 b:容斥原理

分析:

枚举倍数,容斥一下。
附上SWHsz的巨神代码。

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int mod=1e9+7,N=100005;
int f[25][N],t[N],mx,gcd[N],n,m,a[25][N],ans,tt[N];
inline int rd() {
        static int x;x=0;static char ch;ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
        return x;
}
int main() {
        freopen("b.in","r",stdin);
        freopen("b.out","w",stdout);
        scanf("%d%d",&n,&m);
        if(n==1) {
                for(int i=1;i<=m;i++) ans=(ans+rd())%mod;
                cout<<ans<<endl;
                return 0;
        }
        for(int i=1;i<=n;i++) {
                memset(t,0,sizeof t);
                for(int j=1;j<=m;j++) {
                        a[i][j]=rd();
                        t[a[i][j]]++;
                        tt[a[i][j]]++;
                        mx=max(mx,a[i][j]);
                }
                for(int j=1;j<=mx;j++) 
                        for(int k=1;j*k<=mx;k++) 
                        f[i][j]+=t[j*k];
        }
        for(int G=mx;G;G--) {
                gcd[G]=1;
                for(int i=1;i<=n;i++) 
                                gcd[G]=(1ll*gcd[G]*(f[i][G]+1))%mod;
                gcd[G]=(gcd[G]-1+mod)%mod;
                for(int i=2;i*G<=mx;i++) 
                        gcd[G]=(gcd[G]-gcd[i*G]+mod)%mod;
                ans=(ans+1ll*gcd[G]*G%mod)%mod;
        }
        cout<<ans<<endl;
}

猜你喜欢

转载自www.cnblogs.com/ErkkiErkko/p/9790255.html