NOIP 2021 数列
暴力#
下标看起来真的乱,30min 打完暴力:
/*
* @Author: Aisaka_Taiga
* @Date: 2023-10-27 15:32:25
* @LastEditTime: 2023-10-27 16:08:12
* @LastEditors: Aisaka_Taiga
* @FilePath: \Desktop\P7961.cpp
* The heart is higher than the sky, and life is thinner than paper.
*/
#include <bits/stdc++.h>
#define int long long
#define P 998244353
#define N 1000100
using namespace std;
inline int read()
{
int x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){if(c == '-') f = -1; c = getchar();}
while(c <= '9' && c >= '0') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return x * f;
}
int n, m, k, a[N], b[N], ans;
inline int ksm(int x, int y)
{
int res = 1;
while(y)
{
if(y & 1) res *= x;
x *= x, y >>= 1;
}
return res;
}
inline void check(int xx)
{
int cnt = 0, res = 1;
while(xx)
{
if(xx & 1) cnt ++;
xx >>= 1;
}
// for(int i = 1; i <= n; i ++)
// cout << b[i] << " ";
// cout << endl;
if(cnt > k) return ;
for(int i = 1; i <= n; i ++)
res = (res * a[b[i]]) % P;
ans = (ans + res) % P;
return ;
}
inline void dfs(int sum, int cnt)
{
if(cnt == n + 1) return check(sum), void();
for(int i = 0; i <= m; i ++)
{
b[cnt] = i;
dfs(sum + ksm(2, i), cnt + 1);
// b[cnt] = 0;
}
return ;
}
signed main()
{
n = read(), m = read(), k = read();
for(int i = 0; i <= m; i ++) a[i] = read();
dfs(0, 1);
cout << ans << endl;
return 0;
}
/*
8 9 1
499488183 118995914 332316574 399234563 246850128 338768262 489466833 673193710 723933572 12759125
*/
由于太过暴力所以导致他在 O2 以及快速幂的加持下才拿到了 5pts。
正解#
考虑搜索最终每一位上的数选多少个,然后根据组合数计算价值和。
那么我们直接搜肯定过不了,要记忆化,设
接下来处理答案的计算以及下一个搜索的状态。
设当前位选了
而对于
那么最后得出转移方程:
/*
* @Author: Aisaka_Taiga
* @Date: 2023-10-27 15:32:25
* @LastEditTime: 2023-10-27 17:11:25
* @LastEditors: Aisaka_Taiga
* @FilePath: \Desktop\P7961.cpp
* The heart is higher than the sky, and life is thinner than paper.
*/
#include <bits/stdc++.h>
#define int long long
#define P 998244353
#define N 110
#define M 35
using namespace std;
inline int read()
{
int x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){if(c == '-') f = -1; c = getchar();}
while(c <= '9' && c >= '0') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return x * f;
}
int n, m, k, ans, a[N], c[M][M], p[N][M], f[N][M][M][M];
inline int popcnt(int x)//??计算一个数转成二进制后一的个数
{
int res = 0;
while(x)
{
if(x & 1) res ++;
x >>= 1;
}
return res;
}
inline int dfs(int x, int y, int a, int b)//x是当前a的值,y是当前选了的个数
{//a是当前已经处理完的位上的1的个数,b是进位后当前位相当于有多少个2^x
if(y >= n) return a + popcnt(b) <= k;//a是前几个位的1个数,popcnt b是进位产生的1的个数
if(x > m) return 0;//越界了,没有合法方案
if(f[x][y][a][b] != -1) return f[x][y][a][b];//记忆化
int res = 0;//当前状态下的答案
for(int i = 0; i <= n - y; i ++)//一个不选~最多能选的个数
res = (res + dfs(x + 1, y + i, a + ((b + i) & 1), ((b + i) >> 1)) * p[x][i] % P * c[n - y][i] % P) % P;
return f[x][y][a][b] = res;//记忆化
}
signed main()
{
memset(f, -1, sizeof f);
n = read(), m = read(), k = read();
for(int i = 0; i <= m; i ++) a[i] = read();
for(int i = 1; i <= n; i ++)
{
c[i][0] = c[i][i] = 1;
for(int j = 1; j < i; j ++)
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % P;
}//预处理组合数
for(int i = 0; i <= m; i ++)
{
p[i][0] = 1;
for(int j = 1; j <= n; j ++)
p[i][j] = p[i][j - 1] * a[i] % P;
}//预处理a[i]^j
ans = dfs(0, 0, 0, 0);
cout << ans << endl;
return 0;
}
/*
8 9 1
499488183 118995914 332316574 399234563 246850128 338768262 489466833 673193710 723933572 12759125
5 1 1
2 1
*/
作者: 北烛青澜
出处:https://www.cnblogs.com/Multitree/articles/17792607.html
本站使用「CC BY 4.0」创作共享协议,转载请在文章明显位置注明作者及出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!