暑假集训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;
}
posted @ 2022-08-21 18:51  Chen_jr  阅读(29)  评论(0编辑  收藏  举报