暑假集训7
A. One
考场忘了约瑟夫问题,以为是板子, 记得有一个关于二进制的递推式, 然后一直在打表,然后就没有然后了。。
这个不是我看过的那个约瑟夫。。。
考虑最开始有 \(n\) 个人, 现在场上还剩 \(x\) 人, 那么我要把第 \(n - x + 1\) 个人踢走, 踢走之后, 第\(n - x + 2\) 个人变成了 剩余 \(x - 1\) 个人时的第一个人, 通过递归我们能得到幸存者在 \(x - 1\) 个人的标号中的新标号 \(id\), 那么通过上面的关系, 我们可以推出他在剩余 \(x\) 个人时的标号为 \(id + n - x +1\) ,回溯即可求得答案
但是不要写递归, \(1e7\) 直接爆栈
开个数组倒着推回来就行了
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. 砖块
依题意模拟即可
考场只留 \(20min\) 打这个题,果然锅了
输出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. 数字
我以为是个结论题, 发现没有结论后以为是个数位\(DP\),结果他是数论题....
对下面内容存在关于知识点的疑惑,可以复习一下数论(无耻引流)
答案转化为求 \((n!)_{10} \mod 10^3\)
不好求,把 \(10^3\) 拆成 \(2^3 \times 5^3\), 求出答案后 \(crt\) 合并
那么我们现在求
\((n!)_{10} \mod 5^3\)
\((n!)_{10} \mod 2^3\)
发现由于 \(2\) 的倍数很多, 所以 \(n > 5\) 时候 \((n!)_{10} \mod 2^3\) 一直为 \(0\)
所以可以只求
\((n!)_{10} \mod 5^3\)
用 \(exlucas\) 中的方法 我们可以求出 \((n!)_{5} \mod 5^3\)
通过 \(exlucas\) 中的方法还可以求出 \(n!\) 有多少 \(5\) 因子 ,记为 \(c_5\)
\((n!)_{10} = (n!)_{5} \times inv_2^{c_5}\)
那么我们就能得到 \(res = (n!)_{10} \mod 5^3\)
\(crt\) 合并一下就好了,
或者有偷懒写法, 因为答案在 \(1000\) 以内, 我们可以直接枚举 \(2^3\) 的倍数, 选择 \(\mod 5^3 = res\) 的,就是答案
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. 甜圈
分块大法好
对每个块维护连续合法操作 $ l_i, r_i$ 新加操作不是 \(r_i +1\)直接非法,改成 \(-1\)即可
对单点的修改也非常省心
比线段树强多了
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;
}