牛客小白月赛40
B.跳跳跳(区间 DP)
题意
个格子呈环形分布,顺时针方向分别标号为,其中和相邻,每个格子上都有一个正整数,玩家可以选择一个点作为起点开始跳下,第次跳跃,玩家只可以选择当前位置左边或右边最近且尚未被跳跃过的位置进行一次跳跃,并获得的得分,其中为第 次跳跃的位置。
数据范围
\(1<=n<=2000\)
\(1<=a[i]<=2000\)
输入
3
1 1 1
输出
6
分析
如果一个区间被跳完,一定是区间端点是最后一个到达的
代码
const int N = 4000 + 5;
int n, m, k, _;
int a[N];
int dp[N][N];
signed main()
{
// IOS;
while(~ sd(n)){
rep(i, 1, n) sd(a[i]), a[i + n] = a[i];
m = n;
n = n * 2;
rep(i, 1, n) dp[i][i] = a[i];
for(int len = 2; len <= m; len ++){
for(int i = 1; i <= n; i ++){
int j = i + len - 1;
if(j > n) break;
dp[i][j] = max(dp[i][j - 1] + a[j] * (j - i + 1), dp[i + 1][j] + a[i] * (j - i + 1));
}
}
int maxx = 0;
for(int i = 1; i <= n; i ++){
maxx = max(maxx, dp[i][i + m - 1]);
}
pd(maxx);
}
// PAUSE;
return 0;
}
C。数字匹配(暴力)
题意
最近比较喜欢二进制数,她认为对于任意两个正整数,当且仅当的二进制非前导零部分最大连续重合位数时,是匹配的,比如的二进制形式为,的二进制形式为,因此和最大连续重合部分为,故这两个数的最大连续重合位数为。
现在给定一个正整数和一个,求对于所有,满足条件的匹配数
现在给定一个正整数和一个,求对于所有,满足条件的匹配数
数据范围
\((n≤2000,k≤10)\)
输入
6 2
输出
7
分析
每个数变成二进制数并不会超过 \(10\) 位,直接暴力判断每个数 \(i\) 与 \(j∈([0,i-1])\) 中有几个数可以满足重合 \(k\) 位即可,时间复杂度可以是 \(O(n^2logn)\)
代码
const int N = 2000 + 5;
int n, m, k, _;
string s[N];
vector<string> v[N];
string calc(int x)
{
if(x == 0) return "0";
string ans = "";
while(x) ans += ('0' + x % 2), x >>= 1;
return ans;
}
bool sol(int x, int y)
{
for(int i = 0; i < v[x].size(); i ++){
for(int j = 0; j < v[y].size(); j ++){
if(v[x][i] == v[y][j]) return 1;
}
}
return 0;
}
signed main()
{
// IOS;
while(~ sdd(n, k)){
for(int i = 0; i <= n; i ++){
s[i] = calc(i);
for(int j = 0; j + k - 1 < s[i].size(); j ++){
string ans = "";
for(int l = 0; l < k; l ++){
ans += s[i][j + l];
}
v[i].pb(ans);
}
}
int ans = 0;
for(int i = 1; i <= n; i ++){
for(int j = 0; j < i; j ++){
if(sol(i, j)) ans ++;
}
}
pd(ans);
}
// PAUSE;
return 0;
}
H.来点gcd(数论)
题意
给定一个有 个元素的多重集 ,有 个询问,对于每个询问,给出一个整数 ,问是否能选择 的一个非空子集,满足这个子集的 等于,当集合只有一个数时,设这个集合的 就等于这个数,的值为的最大公约数
数据范围
\(1<=n+m<=10^6\)
\(1<=x, a[i]<=n\)
输入
2
7 3
2 2 6 6 2 1 5
3
2
6
7 3
6 3 1 4 6 4 3
7
5
2
输出
NO
YES
YES
NO
NO
YES
分析
如果一个数 \(x\) 可以被一个集合求出来,那么这个集合一定全为 \(x\) 的倍数
又 \(gcd(a, b)<=min(a,b)\),所以对于每个数 \(x\), 如果它所有的倍数构成一个集合仍凑不出来,那么说明 \(x\) 不存在
代码
const int N = 1e6 + 5;
int n, m, k, _;
int a[N];
int d[N];
void clear()
{
rep(i, 1, n){
a[i] = d[i] = 0;
}
}
signed main()
{
// IOS;
rush(){
sdd(n, m);
rep(i, 1, n){
a[read()] = 1;
}
for(int i = 1; i <= n; i ++){
for(int j = i; j <= n; j += i){
if(a[j]){
d[i] = __gcd(d[i], j);
}
}
}
while(m --> 0){
int x = read();
if(d[x] == x) puts("YES");
else puts("NO");
}
clear();
}
// PAUSE;
return 0;
}