暑假第十三测

 

题解:

第一题:

规律可由打表知,需要注意一下容斥原理

#include<bits/stdc++.h>
using namespace std;
const int M = 1e4 + 10;
#define ll long long 
int n; ll m, Ans, num[M], vis[M];
ll a[M], qs[M];
ll gcd(ll a, ll b){
    if(!b)return a;
    return gcd(b, a%b);
}

int main(){
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int T, pp =0;
    scanf("%d", &T);
    while(T--){
        pp++;
        int fg = 0, cnt = 0;
        Ans = 0;
        memset(vis, 0, sizeof(vis));
        memset(num ,0, sizeof(num));
        scanf("%d%I64d", &n, &m);
        for(int i = 1; i * i <= m; i++){
            if(m % i == 0){
                qs[++cnt] = i;    
                if(i * i != m)qs[++cnt] = m/i;
            }
                
        }
        sort(qs+1, qs+1+cnt);
        for(int i = 1; i <= n; i++){
            scanf("%I64d", &a[i]);
            a[i] = gcd(m, a[i]);
            for(int j = 1; j <= cnt; j++){
                if(qs[j] % a[i] == 0)vis[j] = 1;
            }
        }
        for(int i = 1; i <= cnt; i++){
            
            if(vis[i] == num[i])continue;
            ll kk = (m - 1) / qs[i];
            ll tmp = (kk + 1) * qs[i] * kk / 2;
            Ans += tmp*(vis[i] - num[i]);
        //    printf("%I64d %d %I64d 
 ",Ans, qs[i], vis[i] - num[i]);
            for(int j = i + 1; j <= cnt; j++)
                if(qs[j] % qs[i] == 0) num[j] += vis[i] - num[i];
        }
        
        printf("Case #%d: %I64d
",pp, Ans);
        
    }
    
}
View Code

第二题:二进制数位dp, 拆数成二进制,枚举1的个数,最后满足 余数=0 && 该数中出现的1的个数 = 枚举的1的个数

这道题要开unsigned long long ,我开始memset dp -1, 交上去全对,看来没有用到记忆画搜索???反正很玄学就是了

#include<bits/stdc++.h>
using namespace std;
#define ll unsigned long long 
ll dp[73][73][73], bin[72];
int digit[73]; bool vis[73][73][73];
ll dfs(int dep, int f, int yu, int sum, int ss){
    if(!dep){
        return !yu && sum == ss;
    }
    if(vis[dep][yu][sum] && !f)return dp[dep][yu][sum];
    ll tmp = 0;
    int i = f ? digit[dep] : 1;
    for(; i >= 0; i--){
        tmp += dfs(dep -1, f & (i == digit[dep]), (yu + i * bin[dep] % ss )% ss, sum + (i == 1), ss);
    }
    vis[dep][yu][sum] = 1;
    if(!f) dp[dep][yu][sum] = tmp;
    return tmp;
}


ll get(ll n){
    ll ans = 0;
    int cnt = 0;
    while(n){
        digit[++cnt] = n%2;
        n /= 2;
    }
    
    for(int i = 1; i <= 71; i++){
        memset(vis, 0, sizeof(vis));
        ans += dfs(cnt, 1, 0, 0, i);
    }
    return ans;
}

int main(){
    //freopen("b.in","r",stdin);
    //freopen("b.out","w",stdout);
    ll n;
    bin[1] = 1;
    for(int i = 2; i <= 71; i++) bin[i] = bin[i - 1] << 1;
    scanf("%I64dd", &n);
    ll ans = get(n);
    printf("%I64d
", ans);
}
View Code

第三题:

这个做法很巧妙啊~

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
const int M = 1005;
ll l[M], h[M], a[M][M], ansx[M], ansy[M];

int main(){
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++){
            scanf("%I64d", &a[i][j]);
            l[j] += a[i][j];
            h[i] += a[i][j];
        }
    for(int i = 0; i <= n; i++){
        ll x = 2;
        for(int j = i; j; j--, x += 4)
            ansx[i] += h[j] * x * x;
        x = 2;
        for(int j = i + 1; j <= n; j++, x += 4)
            ansx[i] += h[j] * x * x;
    }
    
    for(int i = 0; i <= m; i++){
        ll x = 2;
        for(int j = i; j; j--, x += 4)
            ansy[i] += l[j] * x * x;
        x = 2;
        for(int j = i + 1; j <= m; j++, x += 4)
            ansy[i] += l[j] * x * x;
    }
    ll Ans = 1e18; int x, y;
    for(int i = 0; i <= n; i++)
        for(int j = 0; j <= m; j++)
            if(ansx[i] + ansy[j] < Ans)
                Ans = ansx[i] + ansy[j], x = i, y = j;
    printf("%I64d
%d %d
", Ans, x, y);
}
View Code
原文地址:https://www.cnblogs.com/EdSheeran/p/9463881.html