• Codeforces Round #538 (Div. 2) (CF1114)


    Codeforces Round #538 (Div. 2) (CF1114)

      今天昨天晚上的cf打的非常惨(仅代表淮中最低水平

      先是一路缓慢地才A掉B,C,然后就开始杠D。于是写出了一个O(n^2)的线性dp,然后就wa6,调到结束。结束后发现完全看漏了两句话。噢,起始点!!!

      好吧然后算算自己有可能这一场要变成+0,反正在0左右。
    结束后开始然后开始写D,顺便思考F。结果写完D发现A怎么fst了,然后。。。因为习惯于对相似的语句复制粘贴,有些东西没有改——三句话都在 -a!!!(这个还能过pt?

      好吧想完F以后又顺便看了一下。发现怎么B也fst了???发现好像忘了考虑相同的数的问题。。。

      还好C没有fst。所以大概不多不少,可以把上一场涨的分数给抵掉。

      也是wph学长说的好,这些都是用血换来的教训啊。(但是看错题真的不应该,这是在NOIP就犯过的错啊。


    A. Got Any Grapes?

      这种题目直接做,显然是先尽量供给Andrew,然后是Dmitry,最后是Michal。

      希望大家不要犯我犯过的错误。(以后记得复制粘贴相似内容的时候注意修改全所有该修改的东西啊)

    int x, y, z, a, b, c;
    
    inline void End() {puts("NO"); exit(0);}
    
    int main() {
    	read(a), read(b), read(c);
    	read(x), read(y), read(z);
    	if (x < a) End(); else x -= a;
    	y += x;
    	if (y < b) End(); else y -= b;
    	z += y;
    	if (z < c) End(); else z -= c;
    	puts("YES");
    }
    

    B. Yet Another Array Partitioning Task

      CF上的B题一般都是大胆猜结论题目。

      直接猜结论: 一定可以选齐前 (m cdot k) 大的数。然后分的时候只要凑齐 (m) 个在前 (m cdot k) 大的数中的数,就可以切一块。

      注意一下(也是我fst的原因),如果前 (m cdot k) 中最小的数没有被选全的话,那么分的时候要注意判断一下那个数已经选了多少个,不够选了就不要把它算上去。

    const int N = 2e5 + 7;
    int n, m, k, p, a[N], b[N];
    ll ans;
    std::map<int, int> mp;
    
    int main() {
    	read(n), read(m), read(k); p = m * k; --k;
    	for (int i = 1; i <= n; ++i) read(a[i]), b[i] = a[i];
    	std::sort(b + 1, b + n + 1);
    	for (int i = n - p + 1; i <= n; ++i) ans += b[i], mp[b[i]]++;
    	printf("%I64d
    ", ans);
    	for (int i = 1, cnt = 0; i <= n; ++i) {
    		if (mp.count(a[i]) && mp[a[i]]) ++cnt, --mp[a[i]];
    		if (cnt == m) --k, printf("%d%c", i, " 
    "[k == 0]), cnt = 0;
    		if (!k) return 0;
    	}
    }
    

    C. Trailing Loves (or L'oeufs?)

      在 (b) 进制下末尾有 (k) 个0,那么说明

    [quad b ^ k | n! ]

      于是我们把 (b) 分解质因数

    [(p_1^{k_1} cdot p_2^{k_2} cdot cdots) ^k | n! ]

      于是我们发现

    [k = min{log_{p_1} n!, log_{p_2}{n!}, cdots } ]

      至于说 (log_p{n!}) 怎么求,这个应该是普及组知识了。

    [log_p n!= sum_{i = 1} lfloor frac n {p ^ i} floor ]

    const int N = 1e6 + 7;
    ll n, m, ans = 0x7fffffffffffffff;
    int np[N], p[N], prt, cnt[N];
    
    inline void Make_Prime(int n ){
    	np[0] = np[1] = 1;
    	for (int i = 2; i <= n; ++i) {
    		if (!np[i]) p[++prt] = i;
    		for (int j = 1; j <= prt && i * p[j] <= n; ++j) {
    			np[i * p[j]] = 1;
    			if (i % p[j]) break;
    		}
    	}
    }
    
    inline ll GetNum(ll n, ll x) {
    	ll ans = 0;
    	while (n) ans += n /= x;
    	return ans;
    }
    
    int main() {
    	read(n), read(m);
    	Make_Prime(sqrt(m));
    	ll hkk = m;
    	for (int i = 1; i <= prt; ++i)
    		while (hkk % p[i] == 0) hkk /= p[i], ++cnt[i];
    	for (int i = 1; i <= prt; ++i) if (cnt[i]) SMIN(ans, GetNum(n, p[i]) / cnt[i]);
    	if (hkk > 1) SMIN(ans, GetNum(n, hkk));
    	printf("%I64d
    ", ans);
    }
    

    D. Flood Fill

      这道题一开始没看见起始方块这个东西,一直wa6。

      如果有起始点,那就是区间dp模板了。

      设 (dp[i][j]) 表示 (i..j) 的这段区间全部化成一种颜色的代价。

    [dp[i][j] = left{ egin{align*} &dp[i+1][j-1] &&c[i] = c[j]\ &min{dp[i][j-1], dp[i][j+1]} + 1 &&c[i] eq c[j] end{align*} ight. ]

    const int N = 5000 + 7;
    const int INF = 0x3f3f3f3f;
    
    int n, m, c[N], dp[N][N];
    
    int main() {
    	read(n);
    	for (int i = 1; i <= n; ++i) read(c[i]), SMAX(m, c[i]);
    	n = std::unique(c + 1, c + n +1) - c - 1;
    	for (int i = n; i; --i)
    		for (int j = i + 1; j <= n; ++j)
    			if(c[i] == c[j]) dp[i][j] = dp[i + 1][j - 1] + 1;
    			else dp[i][j] = std::min(dp[i][j - 1], dp[i + 1][j]) + 1;
    	printf("%d
    ", dp[1][n]);
    }
    

    E. Arithmetic Progression

      交互题娱乐身心。

      显然我们一个二分就可以很开心地求出最大值。

      然后我们就可发现,任意两个数的差都应该是公差的倍数。于是我们多随机一些位置,因为前面二分过,所以后面最多问30次左右(当然不能直接问前30个,防止毒瘤会卡),把位置上的值与最大值的差算出来,那么公差一定是它们的约数,有很大的概率是 (gcd)

      不会证明正确率。

    const int N = 1e6 + 7;
    int n, L, R, stp, used[N];
    
    int main() {
    	read(n); srand(time(0));
    	int l = 0, r = 1e9;
    	while (l < r) {
    		int mid = (l + r) >> 1, get;
    		printf("> %d
    ", mid); fflush(stdout);
    		read(get);
    		if(get) l = mid + 1;
    		else r = mid;
    	}
    	R = l;
    	for (int i = 1, get = 0; i <= 30 && i <= n; ++i) {
    		int pos = rand() % n + 1;
    		while(used[pos]) pos = rand() % n + 1;
    		used[pos] = 1;
    		printf("? %d
    ", pos); fflush(stdout);
    		read(get);
    		stp = std::__gcd(stp, R - get);
    	}
    	printf("! %d %d
    ", R - (n - 1) * stp, stp);
    	fflush(stdout);
    }
    

    F. Please, another Queries on Array?

      回顾一下欧拉函数的公式。

    [varphi(n) = n sum_{p ext{是}n ext{质因数}} 1-frac1p ]

      所以我们只需要线段树维护区间乘积,以及每个质数出没出现过。

      一开始打算用bitset,但是发现 (300) 以内质数只有 (62) 个,不多不少,可以直接 ull存。大概 ll也就够了。

      注意区间乘积,乘标记在区间上算贡献要以幂的形式算上去,而不是像求区间和那样直接乘。一开始没注意到,死活过不去。还有如果是用 ull压位的,注意算集合的时候 1 << i要写成1ull << i

    #define lc o << 1
    #define rc o << 1 | 1
    typedef std::pair<ull, int> pli;
    
    const int N = 4e5 + 7;
    const int M = 300 + 7;
    const int P = 1e9 + 7;
    
    int n, m, x, y, z, a[N];
    char opt[15];
    
    int prt, p[M], np[M], inv[N], id[N];
    inline void Make_Prime(int n) {
    	np[0] = np[1] = inv[1] = 1; 
    	for (int i = 2; i <= n; ++i) {
    		inv[i] = (ll)(P - P / i) * inv[P % i] % P;
    		if (!np[i]) p[++prt] = i, id[i] = prt;
    		for (int j = 1; j <= prt && i * p[j] <= n; ++j){
    			np[i * p[j]] = j;
    			if (i % p[j] == 0) break;
    		}
    	}
    }
    
    inline pli operator + (const pli &a, const pli &b) {return pli(a.fi | b.fi, (ll)a.se * b.se % P);}
    inline int fpow(int x, int y) {
    	int ans = 1;
    	for (; y; y >>= 1, x= (ll)x * x % P) if(y & 1) ans = (ll)ans * x % P;
    	return ans;
    }
    
    struct Node {
    	ull val, add;
    	int mul, tag;
    } t[N << 2];
    inline void Build(int o, int L, int R) {
    	t[o].tag = 1;
    	if (L == R) {
    		int x = a[L]; t[o].mul = a[L];
    		while (x > 1 && np[x]) t[o].val |= 1ull << (np[x] - 1), x /= p[np[x]];
    		if (x > 1) t[o].val |= 1ull << (id[x] - 1); return;
    	}
    	int M = (L + R) >> 1;
    	Build(lc, L, M); Build(rc, M + 1, R);
    	t[o].val = t[lc].val | t[rc].val; t[o].mul = (ll)t[lc].mul * t[rc].mul % P;
    }
    inline void Mul(int o, int L, int R, int l, int r, int x, ull y) {
    	if (l <= L && R <= r) {
    		t[o].tag = (ll)t[o].tag * x % P;
    		t[o].mul = (ll)t[o].mul * fpow(x, R - L + 1) % P;
    		t[o].add |= y; t[o].val |= t[o].add; return;
    	}
    	int M = (L + R) >> 1;
    	if (l <= M) Mul(lc, L, M, l, r, x, y);
    	if (r > M) Mul(rc, M + 1, R, l, r, x, y);
    	t[o].val = t[lc].val | t[rc].val | t[o].add;
    	t[o].mul = (ll)t[lc].mul * t[rc].mul % P *fpow(t[o].tag, R - L + 1) % P;
    }
    inline pli Get(int o, int L, int R, int l, int r, pli add = pli(0, 1)) {
    	if (l <= L && R <= r) return pli(t[o].val, t[o].mul) + pli(add.fi, fpow(add.se, R - L + 1));
    	int M = (L + R) >> 1; pli hkk = add + pli(t[o].add, t[o].tag);
    	if (r <= M) return Get(lc, L, M, l, r, hkk);
    	if (l > M) return Get(rc, M + 1, R, l, r, hkk);
    	return Get(lc, L, M, l, r, hkk) + Get(rc, M + 1, R, l, r, hkk);
    }
    
    inline int GetAns(pli x) {
    	int ans = x.se; ull S = x.fi;
    	for (int i = 1; i <= prt; ++i)
    		if((S >> (i - 1)) & 1) ans = (ll)ans * inv[p[i]] % P * (p[i] - 1) % P;
    	return ans;
    }
    
    int main() {
    	#ifdef hzhkk
    	freopen("hkk.in", "r", stdin);
    	#endif
    	read(n), read(m); Make_Prime(300);
    	for (int i = 1; i <= n; ++i) read(a[i]);
    	Build(1, 1, n);
    	for (int i = 1; i <= m; ++i) {
    		scanf("%s", opt); read(x), read(y);
    		if (*opt == 'M') {
    			read(z); ull hkk = 0; int r = z;
    			while (r > 1 && np[r]) hkk |= 1ull << (np[r] - 1), r /= p[np[r]];
    			if (r > 1) hkk |= 1ull << (id[r] - 1);
    			Mul(1, 1, n, x, y, z, hkk);
    		}
    		else printf("%d
    ", GetAns(Get(1, 1, n, x, y)));
    	}
    }
    
  • 相关阅读:
    oracle学习13
    oracle学习12
    oracle学习11
    oracle学习10
    CodeForces
    CodeForces
    UVA
    poj3320 Jessica's Reading Problem
    poj2456 Aggressive cows
    jQuery 鼠标滚轮插件 mousewheel
  • 原文地址:https://www.cnblogs.com/hankeke/p/CF1114.html
Copyright © 2020-2023  润新知