2022NOIPA层联测21
B. 学数学
打表只发现了连续的似乎比较有规律的样子,通过他们算出来的恰好是倍数,如果是“以3为起点的链表”就是.但是不知道有什么用……
于是枚举这个像链表头一样的东西,剩下的另一个数循环一下,每次让等于找到的再继续找。估分.
结果由于没有预处理前缀和,好像不久之前某的还有更多的题都是这么错的……
有更高级的规律:从上一对得到下一对的方式就是,把所有答案的最小值放进数组里排完序二分答案。
有一个细节就是乘法会越界,可以开也可以把它写成除法。
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e7 + 2;
int T, cnt;
ll n, a[maxn];
inline ll read()
{
ll x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
int main()
{
freopen("math.in", "r", stdin);
freopen("math.out", "w", stdout);
n = 1e18; a[++cnt] = 1;
for(ll i=2; i<=1000000; i++)
{
ll k = i * i, x = i;
for(ll y=i*i*i; y<=n; )
{
a[++cnt] = y;
if((n + x) / y < k) break; //写成乘法因为会越界
ll nxty = k * y - x;
x = y; y = nxty;
}
}
sort(a+1, a+1+cnt);
T = read();
while(T--)
{
n = read();
printf("%d\n", upper_bound(a+1, a+1+cnt, n)-a-1);
}
return 0;
}
C. 早该砍砍了
由于我的稳定输出qpow(2, n-1),不会改了就直接交了个这个。。
关于正经的暴力做法,有效的覆盖最多有次,最短的有效区间长度是,每次最少“同化”一个,于是并记录步数,每一步枚举和,记录过程中的每一个状态。
code
// ubsan: undefined
// accoders
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3007;
const int mod = 1e9 + 7;
int n, h[maxn], f[maxn][maxn], ans;
map<int, bool> mp;
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
inline int getsum()
{
int ans = 0;
for(int i=1; i<=n; i++) ans = (ans << 1) + (ans << 3) + h[i];
return ans;
}
void dfs(int now)
{
int sum = getsum();
if(mp.find(sum) == mp.end())
{
mp[sum] = 1; ans++;
}
if(now == n-1) return;
int d[10];
for(int i=1; i<=n; i++) d[i] = h[i];
for(int i=1; i<=n; i++)
{
for(int j=2; i+j-1<=n; j++)
{
int mi = h[i];
for(int k=i+1; k<=i+j-1; k++) mi = min(mi, h[k]);
for(int k=i; k<=i+j-1; k++) h[k] = mi;
dfs(now + 1);
for(int k=i; k<=i+j-1; k++) h[k] = d[k];
}
}
}
void solve()
{
for(int i=1; i<=n; i++) f[n][i] = n - i + 1;
for(int i=n-1; i>=1; i--)
{
for(int j=1; j<=i; j++) f[i][j] = (f[i][j] + f[i+1][j]) % mod;
for(int j=i-1; j>=1; j--) f[i][j] = (f[i][j] + f[i][j+1]) % mod;
}
printf("%d\n", f[1][1]);
exit(0);
}
int main()
{
freopen("cut.in", "r", stdin);
freopen("cut.out", "w", stdout);
n = read(); bool sp = 1;
for(int i=1; i<=n; i++)
{
h[i] = read();
if(h[i] != i) sp = 0;
}
if(sp) solve();
dfs(0);
printf("%d\n", ans);
return 0;
}
鹤了一下……
把看成时间,表示轮到贡献的时候前缀的方案数,每一个点能贡献方案的区间是它作为最小值的区间,并且覆盖不可以跳跃。
从开始如果被覆盖,覆盖前和覆盖后增加的恰好是,再考虑,有是否被覆盖的情况,如果被覆盖了还可以继续讨论,方案数的增量就是,发现可以求前缀和。
code
//任尘世繁华,唯有守护你的一切,才是我此生唯一的使命。
//——次元战争·红龙
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3007;
const int mod = 1e9 + 7;
int f[maxn][maxn], n, a[maxn];
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
void add(int &x, int y) {x += y; x = x >= mod ? x - mod : x;}
int main()
{
freopen("cut.in", "r", stdin);
freopen("cut.out", "w", stdout);
n = read(); for(int i=1; i<=n; i++) a[i] = read();
f[0][0] = 1;
for(int i=1; i<=n; i++)
{
for(int j=0; j<=n; j++) f[i][j] = f[i-1][j];
int l = i, r = i;
for(l=i; l>=1 && a[l]>=a[i]; l--); l++;
for(r=i; r<=n && a[r]>=a[i]; r++); r--;
int now = l ? f[i][l-1] : 0;
for(int j=l; j<=r; j++) add(f[i][j], now), add(now, f[i-1][j]);
}
printf("%d\n", f[n][n]);
return 0;
}
时光花火,水月星辰
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】