Codeforces Round #391 A B C D E
A. Gotta Catch Em' All!
题意
从给定的字符串中选取字符,问可构成多少个\(Bulbasaur\)
// 想到柯南里一些从报纸上剪汉字拼成的恐吓信_(:з」∠)_
Code
#include <bits/stdc++.h>
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
#define maxn 100010
using namespace std;
typedef long long LL;
int cnt[256];
char dict1[] = {'B', 'l', 'b', 's', 'r'};
char dict2[] = {'u', 'a'};
char s[maxn];
int main() {
scanf("%s", s);
int len = strlen(s), ans=len;
F(i, 0, len) ++cnt[s[i]];
F(i, 0, 5) ans = min(ans, cnt[dict1[i]]);
F(i, 0, 2) ans = min(ans, cnt[dict2[i]]>>1);
printf("%d\n", ans);
return 0;
}
B. Bash's Big Day
题意
从\(n\)个数中挑尽可能多的数使得它们的\(gcd\gt 1\)
思路
法一
将每个数质因子分解
法二
对于每个质数,枚举其倍数
注意:特判一个数的情况
Code
Ver. 1: 93ms
#include <bits/stdc++.h>
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
#define maxn 100010
using namespace std;
typedef long long LL;
int cnt[maxn];
void divide(int x) {
for (int i = 2; ; ++i) {
if (i*i>x) break;
if (x%i==0) {
++cnt[i];
while (x%i==0) x /= i;
}
}
if (x>1) ++cnt[x];
}
int main() {
int n, x, ans=0;
scanf("%d", &n);
F(i, 0, n) {
scanf("%d", &x);
divide(x);
}
F2(i, 2, maxn-10) ans = max(ans, cnt[i]);
printf("%d\n", ans?ans:1);
return 0;
}
Ver. 2: 31ms
#include <bits/stdc++.h>
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
#define maxn 100000
using namespace std;
typedef long long LL;
int num[maxn+10], cnt[maxn+10], prime[maxn], tot;
bool vis[maxn+10];
void work(int x) {
for (int i = 1; ; ++i) {
if (i*x>maxn) break;
cnt[x] += num[i*x];
}
}
void init() {
F2(i, 2, maxn) {
if (!vis[i]) prime[tot++] = i;
work(i);
F(j, 0, tot) {
if (i*prime[j]>maxn) break;
vis[i*prime[j]]=true;
if (i%prime[j]==0) break;
}
}
}
int main() {
int n, x, ans=0;
scanf("%d", &n);
F(i, 0, n) {
scanf("%d", &x);
++num[x];
}
init();
F2(i, 0, maxn) ans = max(ans, cnt[i]);
printf("%d\n", ans?ans:1);
return 0;
}
C. Felicity is Coming!
题意
有\(n\)种动物,\(m\)个山洞,每个山洞中有\(g_i\)个动物(种类可重复)。
\(f\)为一个双射,\(f(x)=y\)即将动物\(x\)变成动物\(y\).
求有多少满足条件的\(f\),使得变化之后每个山洞中的动物分布与之前完全相同。
思路
即找对于动物来说,有多少个等价类,每个等价类中可以全排列。
怎么找有多少个等价类呢?
动物\(x\)与动物\(y\)等价,当且仅当它们在每个山洞中的出现次数都相同。
因此,对每个动物开一个\(vector\),表示它们在哪些山洞中出现,出现多次则记录多次。
则,\(x\leftrightarrow y\iff v[x]==v[y]\)
将\(v\)排序即可
Code
#include <bits/stdc++.h>
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
#define maxn 1000010
using namespace std;
typedef long long LL;
int n, m, x, y;
LL f[maxn];
vector<int> v[maxn];
const LL mod=1e9+7;
void init() {
f[0] = 1;
F2(i, 1, m) f[i] = f[i-1]*i%mod;
}
int main() {
scanf("%d%d", &n,&m);
F(i, 0, n) {
scanf("%d", &x);
F(j, 0, x) {
scanf("%d", &y);
v[y].push_back(i);
}
}
init();
sort(v+1, v+1+m);
int cnt=1; LL ans=1;
F2(i, 2, m) {
if (v[i]==v[i-1]) ++cnt;
else {
(ans *= f[cnt]) %= mod;
cnt=1;
}
}
(ans *= f[cnt]) %= mod;
printf("%I64d\n", ans);
return 0;
}
D. Felicity's Big Secret Revealed
题意
将一个长度为\(n\)的\(01\)串\(s\)进行分割,对于\(s_1|s_2|\cdots|s_{k-1}|s_{k}\),其中有效的数字为\(s_2,s_3,\cdots,s_{k-1}\),设其中的最大数为\(m\). 我们称一个分割为有效的,当且仅当\(s_2,s_3,\cdots,s_{k-1}\)连续地构成\(1-m\)的所有数(可重复)。
问有多少个有效的分割。
思路
参考:http://www.cnblogs.com/widsom/p/7417983.html
因为\(n\leq 75\),而1(1 bits) + 2(2 bits) + 4(3 bits) + 8(4 bits) + 5*(5 bits) = 74 bits,故最大数不会超过\(20\),故进行状压\(dp\).
状态\(state\):第\(i\)位为\(1\)当且仅当集合中有该数\(i\)
\(dp[i][j]\)表示最后一刀切在\(i\)之前,得到的集合状态为\(state\)的情况总数。
至于有效的分割怎么处理呢?最后统计答案时直接统计\(state\)为\(2\)的幂次\(-1\)的情况即可,处理中途不用管(也无法管)。
Code
#include <bits/stdc++.h>
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
#define maxn 80
#define maxl 1100000
using namespace std;
typedef long long LL;
const int mod = 1e9+7;
int num[maxn][maxn], n, dp[maxn][maxl];
char s[maxn];
void init() {
F(i, 0, n) {
int x=0;
F(j, i, n) {
num[i][j] = ((x<<=1) += s[j]-'0');
}
}
}
int main() {
scanf("%d%s", &n, s);
init();
int lim=(1<<20)-1;
F2(i, 0, n) {
dp[i][0] = 1;
F(j, 0, lim) {
if (!dp[i][j]) continue;
F2(k, i+1, n) {
if (num[i][k-1]>20) break;
if (!num[i][k-1]) continue;
(dp[k][j|(1<<num[i][k-1]-1)] += dp[i][j]) %= mod;
}
}
}
int ans=0;
F2(i, 0, n) {
F2(j, 1, 20) (ans += dp[i][(1<<j)-1]) %= mod;
}
printf("%d", ans);
return 0;
}
E. Bash Plays with Functions
题意
\(f_0(n)\):有序对\((u,v)\)的个数,满足\(u*v=n\)且\(gcd(u,v)=1\)
\(f_{r+1}(n)=\sum_{u*v=n}\frac{f_r(u)+f_r(v)}{2}\)
给若干组询问\(r,n\),求\(f_r(n)\)
思路
参考:http://www.cnblogs.com/candy99/p/6284051.html
首先,\(f_0(n)\)是什么?
记\(n=p_1^{\alpha_1}*p_2^{\alpha_2}*\cdots*p_k^{\alpha_k}\),则\(u,v\)的选取必然不能有相同的因子,所以情况必然是,\(u\)选择了一部分质数的所有次数,而\(v\)自然就选择了其他所有质数的所有次数。
故\(f_0(n)=2^k\).
显然,\(f_{r+1}(n)=\sum_{u*v=n}\frac{f_r(u)+f_r(v)}{2}=\sum_{u|n}f_r(u)\).
因为\(f_0\)为积性函数,所以\(f_r\)为积性函数,所以$$f_r(n)=f_r(p_1{\alpha_1}*p_2\cdotsp_k{\alpha_k})=f_r(p_1)*f_r(p_2{\alpha_2})*\cdots*f_r(p_k)$$
故只要求\(f_r({p^\alpha})\)即可。
注意到,\(f_0(p^\alpha)=2\)与\(p\)无关,所以可用\(dp[r][\alpha]\)表示\(f_r(p_\alpha)\),\(dp[r]\)为\(dp[r-1]\)的前缀和,预处理出即可。
此外,线性筛时预处理出每个数的最小质因子,即可省得对每个\(n\)枚举因子。
Code
#include <bits/stdc++.h>
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
#define maxn 1000000
#define maxk 20
int dp[maxn+10][maxk+1], lp[maxn+10], prime[maxn], tot;
bool vis[maxn+10];
using namespace std;
typedef long long LL;
const LL mod=1e9+7;
void init() {
F2(i, 2, maxn) {
if (!vis[i]) {
prime[tot++] = i;
lp[i] = i;
}
F(j, 0, tot) {
if (i*prime[j]>maxn) break;
vis[i*prime[j]] = true;
lp[i*prime[j]] = prime[j];
if (i%prime[j]==0) break;
}
}
F2(i, 1, maxk) dp[0][i] = 2;
F2(i, 1, maxn) {
dp[i][0] = 1;
F2(j, 1, maxk) dp[i][j] = (dp[i][j-1] + dp[i-1][j])%mod;
}
}
LL calc(int n, int r) {
LL ans=1;
while (n>1) {
int pr = lp[n], cnt=0;
while (n % pr==0) ++cnt, n/=pr;
(ans *= dp[r][cnt]) %= mod;
}
return ans;
}
int main() {
init();
int T;
scanf("%d", &T);
while (T--) {
int n, r;
scanf("%d%d", &r,&n);
printf("%I64d\n", calc(n, r));
}
return 0;
}