zoukankan      html  css  js  c++  java
  • 「NOIP」 联赛模拟测试34

    666

    用类似与 (BFS) 的思想,从 (1)(6) 的状态向其他状态转移。

    记一个当前走了 (tmp) 步,对于每个已经可以到达的状态向下转移,直到 (f[n] eq -1)

    暴力扫发现,最多会走 (48) 步,所以只用转移 (1sim n+48) 的状态。

    代码

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 2e6 + 50, INF = 0x3f3f3f3f;
    
    inline int read () {
    	register int x = 0, w = 1;
    	register char ch = getchar ();
    	for (; ch < '0' || ch > '9'; ch = getchar ()) if (ch == '-') w = -1;
    	for (; ch >= '0' && ch <= '9'; ch = getchar ()) x = x * 10 + ch - '0';
    	return x * w;
    }
    
    inline void write (register int x) {
    	if (x / 10) write (x / 10);
    	putchar (x % 10 + '0');
    }
    
    int n, m, tmp, f[maxn];
    
    inline void Init () {
    	memset (f, -1, sizeof f), f[1] = 0;
    	while (f[n] == -1) {
    		tmp ++;
    		for (register int i = 1; i <= m; i ++) {
    			if (f[i] == -1) continue;
    			register int j = i + i * (tmp - f[i] - 1);//复制粘贴
    			if (j <= m && j >= 1 && f[j] == -1) f[j] = tmp;
    			if (f[i - 1] == -1) f[i - 1] = f[i] + 1;//退格
    		}
    	}
    }
    
    int main () {
    	freopen ("six.in", "r", stdin);
    	freopen ("six.out", "w", stdout);
    	n = read(), m = n + 48, Init (), printf ("%d
    ", f[n]);
    	return 0;
    }
    

    春思

    还是比较数学的,逼得我直接考场现推约数和定理,印象 (++)然后因为不会质因数分解而劝退。

    约数和定理

    对于一个整数 (T),设可以分解质因数为:

    [T=prod p_i^{a_i} ]

    则它的约数个数为:

    [prod (a_i+1) ]

    证明:

    (T=12),可以分解为 (2^2 imes 3^1)

    那么它的约数是选取若干个质因子 (2) 和若干个质因子 (3) 相乘而的。

    (2) 可以选 (0,1,2) 个, (3) 可以选 (0,1) 个,以此组合,所以它的约数有 (6) 个。

    进而推得一个整数 (T) 的约数个数为:

    [prod (a_i+1) ]

    证毕。

    它的约数和为:

    [prod sum_{j}^{a_i}p_i^j ]

    证明:

    对于每个约数可以表示为:

    [prod p_i^x;(xin [0,a_i]) ]

    则约数和为:

    [sum prod^{a_i}_{x_i=0}p_i^{x_i} ]

    可以转化为:

    [prod sum_{j=0}^{a_i}p_i^j ]

    证毕。

    但是我们要求的是 (a^b) 的约数和,可以直接将 (a) 质因数分解,将每个质因数的次幂都乘上 (b),再用约数和定理求。

    至于中间的 (sum_{j=0}^{a_i}p_i^j),直接用等比序列求和公式求就行了。

    代码

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    
    typedef long long ll;
    
    using namespace std;
    
    const int maxn = 1e6 + 50, INF = 0x3f3f3f3f, mod = 9901;
    
    inline ll read () {
    	register ll x = 0, w = 1;
    	register char ch = getchar ();
    	for (; ch < '0' || ch > '9'; ch = getchar ()) if (ch == '-') w = -1;
    	for (; ch >= '0' && ch <= '9'; ch = getchar ()) x = x * 10 + ch - '0';
    	return x * w;
    }
    
    inline void write (register int x) {
    	if (x / 10) write (x / 10);
    	putchar (x % 10 + '0');
    }
    
    ll a, b, aa, cnt, ans = 1ll;
    ll prime[maxn], num[maxn];
    
    inline ll qpow (register ll a, register ll b) {
    	register ll ans = 1ll;
    	while (b) {
    		if (b & 1) ans = ans * a % mod;
    		a = a * a % mod, b >>= 1;
    	}
    	return ans;
    }
    
    int main () {
    	freopen ("spring.in", "r", stdin);
    	freopen ("spring.out", "w", stdout);
    	a = read(), b = read(), aa = sqrt (a);
    	for (register ll i = 2; i <= aa; i ++) {
    		if (a % i == 0) {
    			prime[++ cnt] = i % mod;
    			while (a % i == 0) num[cnt] ++, a /= i;
    		}
    	}
    	if (a != 1) prime[++ cnt] = a % mod, num[cnt] ++;
    	for (register int i = 1; i <= cnt; i ++) {
    		if (prime[i] == 1) ans = ans * (num[i] * b % mod + 1) % mod; //prime[i] % 9901 = 1 的特判
    		else ans = ans * (qpow (prime[i], num[i] * b + 1) - 1ll) % mod * qpow (prime[i] - 1, mod - 2) % mod;
    	}
    	printf ("%lld
    ", ans);
    	return 0;
    }
    

    密州盛宴

    先假设只让乡亲们吃 (0),不允许他们吃 (1),这样放的话显然是合法的,只是会有多余的步数,现在求出来的最多步数是 (max(num[1] - num[0] -1))

    考虑去掉多余的步骤,我们会发现,(1)(0) 多余的部分是可以让苏东坡和乡亲们一起吃的,所以可以尽量放到前面,把我们换过去的 (0) 换回来,但是放完这多余的,一定要放一个 (0),便是最短的距离,即最多步数减去 (num[1] - num[0])

    代码

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    #define int long long
    
    using namespace std;
    
    const int maxn = 1e6 + 50, INF = 0x3f3f3f3f;
    
    inline int read () {
    	register int x = 0, w = 1;
    	register char ch = getchar ();
    	for (; ch < '0' || ch > '9'; ch = getchar ()) if (ch == '-') w = -1;
    	for (; ch >= '0' && ch <= '9'; ch = getchar ()) x = x * 10 + ch - '0';
    	return x * w;
    }
    
    inline void write (register int x) {
    	if (x / 10) write (x / 10);
    	putchar (x % 10 + '0');
    }
    
    int n, m, num0, num1, ans;
    
    signed main () {
    	freopen ("meal.in", "r", stdin);
    	freopen ("meal.out", "w", stdout);
    	while (1) {
    		n = read(), m = read(), ans = num0 = num1 = 0;
    		if (!n && !m) break;
    		while (m --) {
    			register char str[maxn];
    			scanf ("%s", str + 1);
    			register int tmp0 = 0, tmp1 = 0, maxx = 0, t = read(), len = strlen (str + 1);
    			for (register int i = 1; i <= len; i ++) {
    				if (str[i] == '0') tmp0 ++;
    				else tmp1 ++;
    				maxx = max (maxx, tmp1 - tmp0);
    			}
    			if (tmp1 > tmp0) ans = max (ans, (num1 + tmp1 * (t - 1)) - (num0 + tmp0 * (t - 1)) + maxx - 1);
    			else ans = max (ans, num1 - num0 + maxx - 1);
    			num0 += tmp0 * t, num1 += tmp1 * t;
    		}
    		if (num0 > num1) puts ("-1");
    		else printf ("%lld
    ", max (ans - num1 + num0, 0ll));
    	}
    	return 0;
    }
    

    赤壁情

    借助 (next\_permutation) 和题目中给的 (random\_shuffle) 可以水到 (60;pts)

  • 相关阅读:
    将一个单向链表逆序
    高精度加法
    从反汇编的角度看引用和指针的区别
    冒泡排序
    josephus(约瑟夫)问题
    获取每个进程可打开的最大文件数量
    AIX免费终端的获取
    [转] Linux应用层的定时器Timer
    POD(plain old data)
    char与wchar_t的区别
  • 原文地址:https://www.cnblogs.com/Rubyonly233/p/14011422.html
Copyright © 2011-2022 走看看