首页 > 其他分享 >闲话 23.1.15

闲话 23.1.15

时间:2023-01-15 19:44:51浏览次数:56  
标签:15 mat int 闲话 rep ret 23.1 bse using

闲话

今日推歌:流星一過 / カラスヤサボウ feat. 镜音铃&镜音连

计算几何怎么学?
也不考啊……

没东西好写了,就给大家拜个早年吧!

数学 \(2\)

同样首先感谢大自然的馈赠。

猜拳游戏

修改游戏规则,把平局情况改成一直玩到赢,则己方现在的胜利概率为 \(\frac{win}{win + lose}\)。
然后求解这个东西的最大值可以做 01 分数规划。二分一个 \(\text{mid}\),然后 dp 出 \(win - \text{mid} * lose\) 的最大值即可。这个意义就是赢了得 \(1\) 分,输了扣 \(k\) 分,看己方是否得分 \(\ge 0\)。
可以倒序 dp,dp 状态可以设 \(f(i, j)\) 为玩到第 \(i\) 轮,之前差距为 \(j\) 场时的最大值。可以第二维 \(+n\) 再做。

得到最大值后做高斯消元即可。方程就是 \(f_i = win\times f_{i + 1} + lose \times f_{i - 1}\)。

code
#include <bits/stdc++.h>
using namespace std; 
using pii = pair<int,int>; using vi = vector<int>; using vp = vector<pii>; using ll = long long; 
using ull = unsigned long long; using db = double; using ld = long double; using lll = __int128_t;
#define multi int T; cin >> T; while ( T -- )
#define timer cerr << 1. * clock() / CLOCKS_PER_SEC << '\n';
#define iot ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define rep(i,s,t) for (register int i = (s), i##_ = (t) + 1; i < i##_; ++ i)
#define pre(i,s,t) for (register int i = (s), i##_ = (t) - 1; i > i##_; -- i)
#define eb emplace_back
#define pb pop_back
const int N = 1e3 + 10;
const int inf = 0x3f3f3f3f;
const ll infll = 0x3f3f3f3f3f3f3f3fll;

int n, m1, m2, r[N], p[N], s[N];
db ans, f[N][N << 1];
bool check(db mid) {
	rep(i,0,n-1) f[n + 1][i] = -mid, f[n + 1][n] = 0;
	rep(i,n+1,n<<1) f[n + 1][i] = 1;
	pre(i,n,1) rep(j,0,n<<1) {
		db t1 = 0, t2 = 0, t3 = 0;

		if (j < (n << 1)) t1 += 1. * s[i] / 100 * f[i + 1][j + 1];
		t1 += 1. * r[i] / 100 * f[i + 1][j];
		if (j) t1 += 1. * p[i] / 100 * f[i + 1][j - 1];


		if (j < (n << 1)) t2 += 1. * p[i] / 100 * f[i + 1][j + 1];
		t2 += 1. * s[i] / 100 * f[i + 1][j];
		if (j) t2 += 1. * r[i] / 100 * f[i + 1][j - 1];

		if (j < (n << 1)) t3 += 1. * r[i] / 100 * f[i + 1][j + 1];
		t3 += 1. * p[i] / 100 * f[i + 1][j];
		if (j) t3 += 1. * s[i] / 100 * f[i + 1][j - 1];

		f[i][j] = max( { t1, t2, t3 } );
	} return f[1][n] >= 0;
}

db mat[N][N], x[N];
db gauss(int n) {
	for (int r = 1, c = 1; r <= n and c <= n; ++ r, ++ c) {
		int mx = r;
		rep(i,r+1, n) if (fabs(mat[i][c]) > fabs(mat[mx][c])) mx = i;
		if (mx != r) rep(i,c,n+1) swap(mat[mx][i], mat[r][i]);
		if (!mat[r][c]) continue;
		rep(i,r+1,n) {
			db tmp = mat[i][c] / mat[r][c];
			rep(j,c,n+1) mat[i][j] -= tmp * mat[r][j];
		}
	} rep(i,1,n) x[i] = 0;
	pre(i,n,1) {
		db tmp = mat[i][n + 1];
		rep(j,i+1,n) tmp -= mat[i][j] * x[j];
		x[i] = tmp / mat[i][i];
	} return x[m2];
}

signed main() {
	while (1) {
		cin >> n >> m1 >> m2;
		if (n == 0) break;
		rep(i,1,n) cin >> r[i] >> p[i] >> s[i];
		db l = 0, r = 1e6, mid;
		rep(i,1,45) {
			mid = (l + r) / 2;
			if (check(mid)) l = mid;
			else r = mid;
		} db q = 1. / (1. / l + 1.);
		// memset(mat, 0, sizeof mat);
		rep(i,2,m1+m2-2) mat[i][i] = 1, mat[i][i - 1] = q - 1, mat[i][i + 1] = -q;
		mat[m1 + m2 - 1][m1 + m2 - 1] = 1, mat[m1 + m2 - 1][m1 + m2] = q;
		if (m1 + m2 - 1 > 1) mat[1][2] = -q, mat[1][1] = 1, mat[m1 + m2 - 1][m1 + m2 - 2] = q - 1;
		cout << setprecision(5) << fixed << gauss(m1 + m2 - 1) << '\n';
	}
}



B君的回忆

奇妙题。

容易发现是迭代 \(k\) 次,每次得到的答案会被作为下一次的下标来计算。考虑如何将下标的范围缩小到一个合理的范围内。
发现这个东西在 \(\bmod\ p\) 下是存在循环的,具体可以通过鸽巢原理以及和斐波那契数列相似的转移发现。
这个东西可以通过 bsgs 来求解,复杂度是根号级别的。

复杂度主要出现在一个大数的根号上,思考如何将大数减小。
发现可以首先将合数质因子分解,然后其循环节长度就是其质因子的循环节的 \(\text{lcm}\),证明显然。
具体关于循环节长度的上界可以看 yspm 曾阅读过的写 斐波那契模意义下循环节的文章
可以发现其循环节上界是 \(6\bmod\) 级别的。如果设 \(g(0) = 0, g(1) = 1\) 可以发现 \(g(n)\) 是斐波那契数列的第 \(n\) 项,大概可以得到更紧的上界。

code
#include <bits/stdc++.h>
using namespace std; 
#define int long long
using pii = pair<int,int>; using vi = vector<int>; using vp = vector<pii>; using ll = long long; 
using ull = unsigned long long; using db = double; using ld = long double; using lll = __int128_t;
#define multi int T; cin >> T; while ( T -- )
#define timer cerr << 1. * clock() / CLOCKS_PER_SEC << '\n';
#define iot ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define rep(i,s,t) for (register int i = (s), i##_ = (t) + 1; i < i##_; ++ i)
#define pre(i,s,t) for (register int i = (s), i##_ = (t) - 1; i > i##_; -- i)
#define eb emplace_back
#define pb pop_back
const int N = 1e6 + 10;
const int inf = 0x3f3f3f3f;
const ll infll = 0x3f3f3f3f3f3f3f3fll;
int a, b, n, k, p;
unordered_map<ll,int> hsh, cyc;

int phi(int k) {
	int ret = k;
	for (int i = 2; i * i <= k; ++ i) if (k % i == 0) {
		ret = ret / i * (i - 1); while (k % i == 0) k /= i;
	} if (k > 1) ret = ret / k * (k - 1);
	return ret;
}

struct mat {
	int a[2][2];
	mat() { memset(a, 0, sizeof a); }
	int* operator[] (const int& p) { return a[p]; }
	const int* operator[] (const int& p) const { return a[p]; }
	void clear() { memset(a, 0, sizeof a); }
	void I() { a[0][0] = a[1][1] = 1, a[0][1] = a[1][0] = 0; }  
	bool operator == (const mat& b) {
		return a[0][0] == b[0][0] and a[0][1] == b[0][1] and a[1][0] == b[1][0] and a[1][1] == b[1][1];
	}
	ll gethsh() {
		ll ret = 0;
		rep(i,0,1) rep(j,0,1) ret = ret * 131 + a[i][j];
		return ret;
	}
}unit;

void mul(mat& a, mat& b, int mod) {
	mat ret;
	rep(i,0,1) rep(j,0,1) rep(k,0,1) ret[i][j] = (ret[i][j] + 1ll * a[i][k] * b[k][j]);
	rep(i,0,1) rep(j,0,1) a[i][j] = ret[i][j] % mod;
}

int get(int n, int pnow) {
	mat bse; 
	bse[0][0] = 0, bse[0][1] = pnow - 1, bse[1][0] = 1, bse[1][1] = 3;
	int v[2] = { a % pnow, b % pnow };
	ll tmp[2];
	while (n) {
		if (n & 1) {
			tmp[0] = tmp[1] = 0;
			rep(i,0,1) rep(j,0,1) tmp[j] += 1ll * v[i] * bse[i][j];
			rep(i,0,1) v[i] = tmp[i] % pnow;
		} mul(bse, bse, pnow);
		n >>= 1;
	} return v[0];
} 

int find(int x) {
	if (x == 1) return 1;
	if (cyc.count(x)) return cyc[x];
	int up = x * 4, sq = sqrt(up);
	hsh.clear();
	mat bse, now; now.I();
	bse[0][0] = 0, bse[0][1] = x - 1, bse[1][0] = 1, bse[1][1] = 3;
	rep(i,0,sq-1) {
		hsh[now.gethsh()] = i;
		mul(now, bse, x);
		if (now == unit) return cyc[x] = i + 1;
	}
	bse = now, mul(now, now, x);
	rep(i,2,up/sq) {
		if (hsh.count(now.gethsh())) return cyc[x] = i * sq - hsh[now.gethsh()];
		mul(now, bse, x);
	} assert(0);
}

int div(int p) {
	if (p == 1) return 1;
	int ret = -1;
	for (int i = 2; i * i <= p; ++ i) if (p % i == 0) {
		int cnt = 1, tmp;
		while (p % i == 0) cnt *= i, p /= i;
		tmp = find(i) * cnt / i;
		if (~ret) ret = ret / __gcd(ret, tmp) * tmp;
		else ret = tmp;
	} if (p > 1) {
		int tmp = find(p);
		if (~ret) ret = ret / __gcd(ret, tmp) * tmp;
		else ret = tmp; 
	} return ret;
}

int f(int n, int k, int pnow) {
	if (k == 1) return get(n, pnow);
	return get(f(n, k - 1, div(pnow)), pnow);
}

signed main() {
	unit.I();
	multi {
		cin >> a >> b >> n >> k >> p;
		cout << f(n, k, p) << '\n';
	}
} 



loj2504

《插值》

简单容斥得到答案

\[\sum_{i=0}^{n - 1} \left(\binom{n - i}{m}^2 - \binom{n - i - 1}{m}^2\right) F(i) \]

然后我们发现这个求和是个差分形式,只需要计算这个玩意的前缀和形式即可
也就是

\[\sum_{i=0}^{n - 1} \binom{n - i}{m}^2 F(i) \]

你发现这玩意上界是模数级别的,不能硬莽。考虑一手 \(\binom{n - i}{m}^2\) 是 \(2m\) 次多项式,\(F\) 是 \(m\) 次多项式,因此乘起来就是 \(3m\) 次,作前缀和就是 \(3m + 1\) 次多项式。
考虑插出来这个东西,因此我们就需要得到前 \(3m + 1\) 次项的系数,随后 \(O(m)\) 解决。
求这个东西的前 \(3m + 1\) 次项的话,首先构造 \(F\) 的前 \(3m + 1\) 次项就好办了。考虑拉格朗日插值,也就是

\[F(n) = \sum_{i = 0}^m F(i) \prod_{j \neq i}^m \frac{n - j}{i - j} \]

套路地设

\[G(i) = F(i) \prod_{j \neq i}^m \frac{1}{i - j} \]

于是能得到

\[\begin{aligned} F(n) &= \sum_{i = 0}^m G(i) \prod_{j \neq i}^m (n - j) \\ &= \sum_{i = 0}^m \frac{1}{i - j} \prod_{j = 1}^m G(i) (n - j) \\ &= \prod_{j = 1}^m (n - j)\sum_{i = 0}^m \frac{G(i) }{i - j} \\ &= \left(\prod_{j = 1}^m (n - j)\right) \left(\sum_{i = 0}^m \frac{G(i) }{i - j} \right) \end{aligned}\]

\(G\) 可以通过逆元前缀积以及讨论 \(-1\) 奇偶性得到,随后只需卷上 \(\dfrac{1}{i}\) 即可。最后可以轻易处理 \(F\)。
随后只需要动态维护 \(\dbinom{i}{m}\) 得到辅助多项式,再卷上 \(F\) 即可得到所需要的前缀和。

最后做两次拉格朗日插值即可。总时间复杂度为 \(O(n\log n)\)。
当然跑得很慢。

Submission.

标签:15,mat,int,闲话,rep,ret,23.1,bse,using
From: https://www.cnblogs.com/joke3579/p/chitchat230115.html

相关文章

  • 洛谷P1157 组合的输出
    原题链接题解:本题有两种办法解决,第一种使用stl中next_permutation函数#include"iostream"#include"algorithm"#include"iomanip"usingnamespacestd;intmai......
  • 力扣每日一题2023.1.12---1807. 替换字符串中的括号内容
    给你一个字符串 s ,它包含一些括号对,每个括号中包含一个非空 的键。   比方说,字符串 "(name)is(age)yearsold" 中,有 两个 括号对,分别包含键 "name"和 "age"......
  • CF1536F. Omkar and Akmar
    牛B题首先因为n>=2,可以发现后手必胜:①当n为偶数时,后手跟着先手走对称,按照n和1的分界线作为对称轴,位置对称+棋子反转②当n为奇数时,设先手走x,后手走x+2,按照x+1作为对称......
  • GYM 101522 La Salle-Pui Ching Programming Challenge 培正喇沙編程挑戰賽 2017
    C.Cheering题意:判断一个字符串中\(LSC\),\(PCMS\)哪个字符穿出现的次数多,如果一样多输出\(Tie\)思路:模拟就行signedmain(){std::strings;......
  • POI2015
    KUR首先设\(z=ai+b\),考虑求出\(z\)的范围。假设序列的第\(j\)位为\(1\),则\(z+a(j-1)\geqp\),即将\([p,n)\)区间向左循环位移\(a(j-1)\),然后对所有这样的区间取交。由于循......
  • 算法--2023.1.15
    1.力扣198--打家劫舍classSolution{publicintrob(int[]nums){intn=nums.length;int[]dp=newint[n+1];dp[0]=0;......
  • AtCoder Regular Contest 153
    喜提全场独一无二的score!ATC还是很友善的,如果每题等分就寄了A签到B真的是凭着实力不会做的呀。。。太菜了发现两维可以分别做,所以考虑一维的情况,然而并不会对于两......
  • 静默安装Oracle11gR2 [FATAL] [INS-32015]报错
    Centos6.5静默安装oracle11gR2[oracle@oracledbdatabase]$./runInstaller-silent-force-responseFile/opt/database/response/db_install.rspStartingOracleU......
  • 2023.1.15;周日复盘
    复盘目的:复习,简洁,高效想法做事情要考虑目的与后果这样提醒自己更专注当下的原本的事情,不被其他事情被打扰,不忘初心;做好做这件事情可能出现的所有结果的心理准备。To......
  • 【随记】2023-1-15 生活感想
    眨眼睛进入it行业也有5年之久,一直没什么成绩,也找不到方向和目标。因为这个原因,一度抑郁,看不到未来。比我年轻的人陆陆续续涌入这个行业,我能做的活他们也能做,甚至比我做得更......