暑假集训7
A. One
考场忘了约瑟夫问题,以为是板子, 记得有一个关于二进制的递推式, 然后一直在打表,然后就没有然后了。。
这个不是我看过的那个约瑟夫。。。
考虑最开始有 个人, 现在场上还剩 人, 那么我要把第 个人踢走, 踢走之后, 第 个人变成了 剩余 个人时的第一个人, 通过递归我们能得到幸存者在 个人的标号中的新标号 , 那么通过上面的关系, 我们可以推出他在剩余 个人时的标号为 ,回溯即可求得答案
但是不要写递归, 直接爆栈
开个数组倒着推回来就行了
code
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<random>
#include<cassert>
using namespace std;
const int maxn = 1e7 + 10;
inline int read(){
int x = 0; char c = getchar();
while(c < '0' || c > '9')c = getchar();
do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c <= '9' && c >= '0');
return x;
}
int a[maxn];
int work(int n){
a[1] = 1;
for(int i = 2; i <= n; ++i){
a[i] = ((n - i + 1) + a[i - 1]) % i;
a[i] = a[i] ? a[i] : i;
}
return a[n];
}
int main(){
int t = read();
for(int i = 1; i <= t; ++i)printf("%d\n",work(read()));
return 0;
}
B. 砖块
依题意模拟即可
考场只留 打这个题,果然锅了
输出for(int i = 1; i <= hi; ++i)printf("\%d ",dy + hi)
我是**
code
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<random>
#include<cassert>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int maxn = 105;
const int base = 1000;
int mp[2005][2005], hi, len;
char c[maxn];
void work(){
int dx = 0, dy = 0, op = 1;
mp[base][base] = 1;
for(int i = 1; i <= len; ++i){
if(c[i] == 'N'){
if(op == 1){++dy; for(int k = 0; k < hi; ++k)++mp[base + dx][base + dy + k]; op = 2;}
else if(op == 2){dy = dy + hi; ++mp[base + dx][base + dy];op = 1;}
else if(op == 3){++dy; for(int k = 0; k < hi; ++k)++mp[base + dx + k][base + dy];}
}
if(c[i] == 'S'){
if(op == 1){dy = dy - hi; for(int k = 0; k < hi; ++k)++mp[base + dx][base + dy + k]; op = 2;}
else if(op == 2){--dy; ++mp[base + dx][base + dy];op = 1;}
else if(op == 3){--dy; for(int k = 0; k < hi; ++k)++mp[base + dx + k][base + dy];}
}
if(c[i] == 'E'){
if(op == 1){++dx; for(int k = 0; k < hi; ++k)++mp[base + dx + k][base + dy];op = 3;}
else if(op == 2){++dx; for(int k = 0; k < hi; ++k)++mp[base + dx][base + dy + k];}
else if(op == 3){dx = dx + hi; ++mp[base + dx][base + dy]; op = 1;}
}
if(c[i] == 'W'){
if(op == 1){dx = dx - hi;for(int k = 0; k < hi; ++k)++mp[base + dx + k][base + dy]; op = 3;}
else if(op == 2){--dx; for(int k = 0; k < hi; ++k)++mp[base + dx][base + dy + k];}
else if(op == 3){--dx; ++mp[base + dx][base + dy]; op = 1;}
}
}
int mx = 1;
for(int i = 1; i <= 2000; ++i)
for(int j = 1; j <= 2000; ++j){
mx = max(mx, mp[i][j]);
mp[i][j] = 0;
}
if(op == 1){
printf("%d\n%d\n",dx,dy);
}
if(op == 2){
for(int i = 1; i <= hi; ++i)printf("%d ",dx);printf("\n");
for(int i = 1; i <= hi; ++i)printf("%d ",dy + i - 1);printf("\n");
}
if(op == 3){
for(int i = 1; i <= hi; ++i)printf("%d ",dx + i - 1);printf("\n");
for(int i = 1; i <= hi; ++i)printf("%d ",dy);printf("\n");
}
printf("%d\n",mx);
}
int main(){
int t; scanf("%d",&t);
for(int ask = 1; ask <= t; ++ask){
scanf("%d%s",&hi,c + 1);
len = strlen(c + 1);
work();
}
return 0;
}
C. 数字
我以为是个结论题, 发现没有结论后以为是个数位,结果他是数论题....
对下面内容存在关于知识点的疑惑,可以复习一下数论(无耻引流)
答案转化为求
不好求,把 拆成 , 求出答案后 合并
那么我们现在求
发现由于 的倍数很多, 所以 时候 一直为
所以可以只求
用 中的方法 我们可以求出
通过 中的方法还可以求出 有多少 因子 ,记为
那么我们就能得到
合并一下就好了,
或者有偷懒写法, 因为答案在 以内, 我们可以直接枚举 的倍数, 选择 的,就是答案
code
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<random>
#include<cassert>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> pii;
const ll maxn = 1005;
const int base = 10000;
const int block = 4;
inline ll read(){
ll x = 0; char c = getchar();
while(c < '0' || c > '9')c = getchar();
do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c <= '9' && c >= '0');
return x;
}
char c[maxn];
struct big{
int a[maxn];
big(){clear();}
void clear(){memset(a, 0, sizeof(a));}
void in(){
clear();
scanf("%s",c + 1);
int len = strlen(c + 1);
a[0] = (len + block - 1) / block;
for(int i = 1; i <= len; ++i){
int j = (len - i + block) / block;
a[j] = a[j] * 10 + (c[i] ^ 48);
}
while(a[a[0]] == 0 && a[0]) --a[0];
}
friend big operator / (big a, const int x){
int res = 0;
for(int i = a.a[0]; i > 0; --i){
res = res * base + a.a[i];
a.a[i] = res / x; res %= x;
}
while(!a.a[a.a[0]] && a.a[0]) --a.a[0];
return a;
}
int operator % (const int x)const{
int res = 0;
for(int i = a[0]; i > 0; --i){
res = res * base + a[i];
res %= x;
}
return res;
}
}a;
int qpow(int x, int y, int mod){
int ans = 1;
for(; y; y >>= 1, x = x * x % mod)if(y & 1)ans = ans * x % mod;
return ans;
}
int get_f(big now, int p, int pk){
if(now.a[0] == 0)return 1;
int res = 1, ls = now % pk, num;
for(int i = 2; i <= ls; ++i)if(i % p)res = res * i % pk;
num = res;
for(int i = ls + 1; i < pk; ++i)if(i % p)res = res * i % pk;
return get_f(now / p, p, pk) * qpow(res, (now / pk) % 100, pk) % pk * num % pk;
}
int getc5(){
int c5 = 0; big b; b = a;
while(b.a[0]){c5 = (c5 + (b / 5) % 100) % 100; b = b / 5;}
return c5;
}
int work(){
if(a.a[0] == 1 && a.a[0] <= 5){
int n = a.a[1], cnt = 0; ll ans = 1;
for(int i = 2; i <= n; ++i){
int now = i; while(now % 5 == 0)now /= 5, ++cnt;
ans = ans * now;
while(cnt && ans % 2 == 0)ans = ans / 2, --cnt;
ans %= 100000;
}
return ans % 1000;
}
int c5 = getc5();
int res = get_f(a, 5, 125);
int mod125 = res * qpow(63, c5 % 100, 125) % 125;
for(int i = 8; i <= 1000; i += 8)if(i % 125 == mod125)return i;
}
int main(){
int t; scanf("%d",&t);
for(int ask = 1; ask <= t; ++ask){
a.in(); int k; scanf("%d",&k);
if(k == 1)printf("%d\n",work() % 10);
if(k == 2)printf("%02d\n",work() % 100);
if(k == 3)printf("%03d\n",work() % 1000);
}
return 0;
}
D. 甜圈
分块大法好
对每个块维护连续合法操作 新加操作不是 直接非法,改成 即可
对单点的修改也非常省心
比线段树强多了
code
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<random>
#include<cassert>
#include<cmath>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int maxn = 200005;
const int maxb = 505;
inline int read(){
int x = 0; char c = getchar();
while(c < '0' || c > '9')c = getchar();
do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c <= '9' && c >= '0');
return x;
}
int block[maxn], l[maxb], r[maxb], now[maxn], n, k, len;
void push_down(int blo){
if(l[blo]){
int pl = (blo - 1) * len + 1, pr = min(blo * len, n);
for(int i = pl; i <= pr; ++i){
if(now[i] + 1 == l[blo])now[i] = r[blo];
else now[i] = -1;
}
l[blo] = r[blo] = 0;
}
}
void modify_one(int ll, int rr, int x){
for(int i = ll; i <= rr; ++i){
if(now[i] + 1 == x)++now[i];
else now[i] = -1;
}
}
void solve(int ll, int rr, int x){
push_down(block[ll]); push_down(block[rr]);
if(block[ll] == block[rr]){modify_one(ll, rr, x);return;}
modify_one(ll, min(block[ll] * len, n), x);
modify_one((block[rr] - 1) * len + 1, rr, x);
for(int i = block[ll] + 1; i < block[rr]; ++i){
if(l[i] != -1){
if(l[i] == 0)l[i] = r[i] = x;
else{
if(r[i] + 1 == x)++r[i];
else l[i] = r[i] = -1;
}
}
}
}
int main(){
n = read(); k = read();
len = sqrt(n);
for(int i = 1; i <= n; ++i)block[i] = (i + len - 1) / len;
int t = read();
for(int ask = 1; ask <= t; ++ask){
int ll = read(), rr = read(), x = read();
solve(ll, rr, x);
}
for(int i = 1; i <= block[n]; ++i)push_down(i);
int ans = 0;
for(int i = 1; i <= n; ++i)if(now[i] == k)++ans;
printf("%d\n",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】