CSP-S模拟4复盘

T1

问题描述

蔡老板最近迷上了下取整函数,即 f(x)=⌊x⌋,它表示不大于 x 的最大整数。

例如:⌊3.6⌋=3,⌊2⌋=2,⌊−2.7⌋=−3​。

蔡老板有一个有理数 x=pq,他用 x 制造了一个序列 a=⌊x⌋,⌊2x⌋,⌊3x⌋,…。形式化地说,ai=⌊x⋅i⌋​。

为了研究这个序列的性质,他尤其关注序列里没有出现过的非负整数。

现在,他想考考你。请你告诉他序列里没有出现过的、第 k 小的非负整数。特别地,如果不存在 k 个这样的数,则答案为 −1。

蔡老板会向你提出 T 个相互独立的问题。

输入格式

第一行包含一个整数 T,表示蔡老板向你提出的问题数量。

接下来 T 行,每行 3 个整数 pi,qi,ki,代表了【问题描述】中的 p,q,k。

输出格式

对每次询问,输出一行一行整数,表示答案。

请注意:因为本题输入输出量过大,我们提供了一个快速输入输出的模板,见下发文件中的 fastio.cpp。这份代码重写了 cin, cout。用法是,你只需要把 fastio.cpp 里面的内容全部复制到你的代码里,然后在代码中正常使用 cin,cout 输入、输出即可。使用这份代码后,请不要用 ios::sync_with_stdio(0);,cin.tie(0); cout.tie(0) 等代码关闭同步。见 sample.cpp 作为一个示范。

思路

们二分答案。考虑0~mid里有多少数在序列里出现过。这个数量就等于ceil((mid+1)*q/p)+1

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
/* --------------- fast io --------------- */ // begin
namespace Fread {
const int SIZE = 1 << 21;
char buf[SIZE], *S, *T;
inline char getchar() {
	if (S == T) {
		T = (S = buf) + fread(buf, 1, SIZE, stdin);
		if (S == T) return '\n';
	}
	return *S++;
}
} // namespace Fread
namespace Fwrite {
const int SIZE = 1 << 21;
char buf[SIZE], *S = buf, *T = buf + SIZE;
inline void flush() {
	fwrite(buf, 1, S - buf, stdout);
	S = buf;
}
inline void putchar(char c) {
	*S++ = c;
	if (S == T) flush();
}
struct NTR {
	~ NTR() { flush(); }
} ztr;
} // namespace Fwrite
#ifdef ONLINE_JUDGE
#define getchar Fread :: getchar
#define putchar Fwrite :: putchar
#endif
namespace Fastio {
struct Reader {
	template<typename T>
	Reader& operator >> (T& x) {
		char c = getchar();
		T f = 1;
		while (c < '0' || c > '9') {
			if (c == '-') f = -1;
			c = getchar();
		}
		x = 0;
		while (c >= '0' && c <= '9') {
			x = x * 10 + (c - '0');
			c = getchar();
		}
		x *= f;
		return *this;
	}
	Reader& operator >> (char& c) {
		c = getchar();
		while (c == ' ' || c == '\n') c = getchar();
		return *this;
	}
	Reader& operator >> (char* str) {
		int len = 0;
		char c = getchar();
		while (c == ' ' || c == '\n') c = getchar();
		while (c != ' ' && c != '\n' && c != '\r') { // \r\n in windows
			str[len++] = c;
			c = getchar();
		}
		str[len] = '\0';
		return *this;
	}
	Reader(){}
} cin;
const char endl = '\n';
struct Writer {
	template<typename T>
	Writer& operator << (T x) {
		if (x == 0) { putchar('0'); return *this; }
		if (x < 0) { putchar('-'); x = -x; }
		static int sta[45];
		int top = 0;
		while (x) { sta[++top] = x % 10; x /= 10; }
		while (top) { putchar(sta[top] + '0'); --top; }
		return *this;
	}
	Writer& operator << (char c) {
		putchar(c);
		return *this;
	}
	Writer& operator << (char* str) {
		int cur = 0;
		while (str[cur]) putchar(str[cur++]);
		return *this;
	}
	Writer& operator << (const char* str) {
		int cur = 0;
		while (str[cur]) putchar(str[cur++]);
		return *this;
	}
	Writer(){}
} cout;
} // namespace Fastio
#define cin Fastio :: cin
#define cout Fastio :: cout
#define endl Fastio :: endl
/* --------------- fast io --------------- */ // end
int t; 
signed main()
{
	cin>>t;
	while(t--){
		int p,q,k;
		int ans=0;
		cin>>p>>q>>k;
		if (p==q){
			if (k==1) cout<<0<<"\n";
			else cout<<-1<<"\n";
		}
		else if (p<q) cout<<-1<<"\n";
		else{
			int l=0,r=1e18;
			while(l<=r){
				int mid=l+r>>1;
				__int128 check=((__int128)(mid+1)*q-1)/p;
				if (mid+1-check>=k){
					r=mid-1;
					ans=mid;
				}
				else{
					l=mid+1;
				}
			}
			cout<<ans<<"\n";
		}
	}
	return 0;
}

T2

小 D 有一座城堡。城堡里面有 n 个房间,每个房间上都写着一个数字 pi。

小 D 拉着几个小伙伴在城堡里面玩耍,他们约定:如果某个人当前站在 i 房间里面,下一步这个人就会去 pi 房间,再下一步这个人去 ppi…

为了增加趣味性,小 D 想重新书写每个房间的 pi,以满足:

如果从编号 1 到 k 中的某个房间开始,按照规则走,必须能够走到 1 号房间。 特别地,如果从 1 号房间开始走,也要能够走回 1 号房间(至少走一步,如果 p1=1,从 1 走到 1 也算合法)。
如果从编号大于 k 的某个房间开始,按照规则走,一定不能走到 1 号房间。
小 D 想知道,有多少种书写 pi​ 的方案,可以满足要求。答案对 10^9+7​ 取模。

思路

有n个点,每个点有一条出边。要求前k个点能走到1号点,后n-k个点不能走到一号点,问方案数。
要爆搜前k个点连接的方案,然后检查;后(n-k)个点,只要连的是后(n-k)个点,爱怎么连怎么连,方案数是 (n-k)^n-k。 最后把两部分方案数乘起来就行。

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=20;
const int mod=1e9+7;
int n,k,p[N],ans;
bool b[N];
int ksm(int a,int b){
	int ans=1;
	while(b){
		if (b&1){
			ans=(ans*a)%mod;
		}
		b>>=1;
		a=(a*a)%mod;	
	}
	return ans;
}
bool check(){
	for (int i=1;i<=k;i++){
		int j=i;
		memset(b,0,sizeof b);
		while(j!=1){
			if (b[j]) break;
			b[j]=true;
			j=p[j];
		}
		if (j!=1) return false;
	}
	return true;
}
void dfs(int x){
	if (x==k+1){
		ans=ans+check();
		return;
	}
	for (int i=1;i<=k;i++){
		p[x]=i;
		dfs(x+1);
	}
}
signed main()
{
	cin>>n>>k;
	int lf=ksm(n-k,n-k)%mod;
	dfs(1);
	cout<<(ans%mod*lf)%mod;
	return 0;
}

T4

滤过

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值