多校赛2017 R2

#多校赛2017#

HDU6052

Problem

Dear Liao

I never forget the moment I met with you. You carefully asked me: “I have a very difficult problem. Can you teach me?”. I replied with a smile, “of course”. You replied:”Given a matrix, I randomly choose a sub-matrix, what is the expectation of the number of different numbers it contains?”

Sincerely yours,
Guo

题意

问一个矩阵中的所有子矩阵中不同数的个数的和。

思路

借鉴了WZJRJ28大佬的思路,考虑每个方块对答案的贡献,需要找到所有包含此方格且不包含与其颜色相同且在他左上方的方格的子矩阵个数,
可以使用单调栈来解决这个问题,单调栈用来解决某一行l列到r列范围内所有不包含(与当前点颜色相同且在其左上方的点)的矩阵的个数。

#include

using namespace std;

const int maxn = 105;
const int maxn2 = 10005;
typedef pair<int,int> p;

int a[maxn][maxn];
int lst[maxn2][maxn]; //lst[i][j]表示第i种颜色在第j列最后出现的行号
int lst2[maxn2][maxn]; //倒数第二次出现
p Stack[maxn];

long long Solve(int l, int r, int i, int j, int clr) {
    //Solve表示l到r范围内所有不包含(与当前点颜色相同且在其左上方的点)的矩阵的个数
    int top = 0;
    long long sum = 0, res = 0;
    for(int k = l; k <= r; k++) {
        int dis = (i == lst[clr][k] && k >= j) ? i - lst2[clr][k]: i - lst[clr][k];
        //dis表示该颜色在k列向上走能到达的最高距离
        if(!dis) {top = sum = 0; continue;} // 可加可不加 加了可以稍微快一点?
        p now = p(dis, 1); //距离和宽度
        while(top && Stack[top-1].first > now.first) {
            sum -= 1ll*Stack[top-1].first * Stack[top-1].second;
            now.second += Stack[top-1].second;
            top--;
        }
        sum += 1ll*now.first * now.second;
        Stack[top++] = now;
        res += sum;
    }
    return res;
}

int main() {
    //freopen("1008.in","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--) {
        long long ans = 0;
        int n, m;
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                scanf("%d",&a[i][j]);
            }
        }
        memset(lst, 0, sizeof(lst));
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                lst2[a[i][j]][j] = lst[a[i][j]][j];
                lst[a[i][j]][j] = i;
            }
            for(int j = 1; j <= m; j++) {
                int clr = a[i][j];
                ans += (n - i + 1ll) * //上方计数完成后下方可直接拓展为n-i+1种情况
                    (Solve(1,m,i,j,clr) - Solve(1,j-1,i,j,clr) - Solve(j+1,m,i,j,clr));
                //求经过当前点单调上升的举行区域中矩形个数需要减去两边的
            }
        }
        printf("%.9f\n",ans*4.0/(n*(n+1)*m*(m+1)));
    }
}

HDU6053

Problem

You are given an array A , and Zhu wants to know there are how many different array B satisfy the following conditions?

  • 1≤Bi≤Ai
  • For each pair( l , r ) (1≤l≤r≤n) , gcd(bl,bl+1…br)≥2

题意

如英文题面。

思路

枚举GCD的值,枚举其倍数,并找到[gcd*i,gcd*(i+1))中的数个个数,对当前GCD=gcd时答案的贡献为i^num,但是会有重复的情况,比如gcd=2时会把gcd=6的情况计算掉,对于枚举的每个gcd对应的答案,最后一个一定是不会多余计算的,可以从后向前依次减去后面是其倍数的答案值。

#include

using namespace std;

const int maxn = 1e5 + 5;
const int mod = 1e9 + 7;
int a[maxn], c[maxn];
const int MOD = mod;
typedef long long ll;
ll ans[maxn];

ll mpow(ll a,ll b)
{
    ll ans = 1;
    a %= MOD;
    while(b > 0)
    {
        if(b&1) ans = (ans*a)%MOD;
        b >>= 1;
        a = (a*a)%MOD;
    }
    return ans;
}

int main() {
    //freopen("1009.in","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--) {
        int n;
        scanf("%d",&n);
        memset(c, 0, sizeof(c));
        int mina = 0x7fffffff, maxa = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%d",&a[i]);
            mina = min(mina, a[i]);
            maxa = max(maxa, a[i]);
            c[a[i]]++;
        }
        for(int i = 1; i <= maxa; i++) c[i] += c[i-1];
        for(int i = 2; i <= mina; i++) {
            ans[i] = 1;
            int t = 1;
            for(int j = i; j <= maxa; j += i) {
                int l = j, r = min(j + i - 1, maxa);
                ans[i] = ans[i] * mpow(t, c[r] - c[l-1]) % mod;
                t++;
            }
        }
        for(int i = mina; i >= 2; i--) {
            for(int j = 2*i; j <= mina; j += i) {
                ans[i] = (ans[i] - ans[j] + mod ) % mod;
            }
        }
        ll res = 0;
        for(int i = 2; i <= mina; i++) res = (res + ans[i]) % mod;
        static int cs = 1;
        printf("Case #%d: %I64d\n",cs++,res);
    }
}

HDU6046

Problem

Qscqesze is busy at data cleaning.
One day,he generates a large matrix by Jenkins one-at-a-time hash:
inline unsigned sfr(unsigned h, unsigned x) {
return h >> x;
}
int f(LL i, LL j) {
LL w = i * 1000000ll + j;
int h = 0;
for(int k = 0; k < 5; ++k) {
h += (int) ((w >> (8 * k)) & 255);
h += (h << 10);
h ^= sfr(h, 6);
}
h += h << 3;
h ^= sfr(h, 11);
h += h << 15;
return sfr(h, 27) & 1;
}
Obviously,it’s a 1e6*1e6 matrix.The data is at row i column j is f(i,j).Note that i and j are both numbered from 1.
Then he gets some matrices sized 1e3*1e3 from the matrix above.But he forgets their original postion.Can you help him to find them out?You just are asked to tell Qscqesze the left-top corner’s postion.

题意

给一个1e6x1e6的01矩阵,再给1e3x1e3的矩阵,让你找这个1e3矩阵所在的位置

思路

在1e6的矩阵中枚举这样的小方阵(边长L),由葛巢原理,2L+DIS<=1000时,总有一个小矩阵会处于1e3的方阵中,用unordered_map或者按顺序存一下1e3中所有的8X8子矩阵可能的情况和其位置,就可以找出枚举的小矩阵相对于大矩阵的相对位置。(可能有两个小矩阵处于1e3不同位置,目前只存了一个,觉得可能会对结果造成不错误的影响,解决方案是都存下来?)

#include

using namespace std;

typedef long long LL;
typedef pair<int,int> p;

inline unsigned sfr(unsigned h, unsigned x) {
  return h >> x;
}
int f(LL i, LL j) {
  LL w = i * 1000000ll + j;
  int h = 0;
  for(int k = 0; k < 5; ++k) {
    h += (int) ((w >> (8 * k)) & 255);
    h += (h << 10);
    h ^= sfr(h, 6);
  }
  h += h << 3;
  h ^= sfr(h, 11);
  h += h << 15;
  return sfr(h, 27) & 1;
}

const int N = 1005;
char s[N][N];
unordered_map M;

int main() {
    freopen("1002.in","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--) {
        M.clear();
        for(int i = 0; i < 1000; i++) scanf("%s",s[i]);
        for(int i = 0; i < 1000 - 7; i++) {
            for(int j = 0; j < 1000 - 7; j++) {
                LL temp = 0;
                for(int k = 0; k < 8; k++) {
                    for(int l = 0; l < 8; l++) {
                        temp <<= 1;
                        if(s[k+i][l+j] == '1') temp |= 1;
                    }
                }
                M[temp] = p(i,j);
            }
        }
        printf("size=%d\n",M.size());
        static int cs = 1;
        bool found = false;
        for(int i = 0; i + 7 < 1000000 && !found; i += 984) {
            for(int j = 0; j + 7 < 1000000 && !found; j += 984) {
                LL temp = 0;
                for(int k = 0; k < 8; k++) {
                    for(int l = 0; l < 8; l++) {
                        temp <<= 1;
                        if(f(k+i,l+j)) temp |= 1;
                    }
                }
                if(M.find(temp) != M.end()) {
                    p res = M[temp];
                    int x = i - res.first, y = j - res.second;
//                    int gg = 0;
//                    for(int ii = 0; ii <1000 && !gg; ii++) {
//                        for(int jj = 0; jj < 1000 && !gg; jj++) {
//                            if(s[ii][jj] != f(ii+x,jj+y)) gg = 1;
//                        }
//                    }
//                    if(gg) continue;
                    printf("Case #%d :%d %d\n",cs++,x,y);
                    found = true;
                }
            }
        }
    }
}

你可能感兴趣的:(多校赛2017,单调栈,容斥)