大集训模拟赛十一

T1 解方程

题目大意

解出一元二次方程ax+by=c的一组解(x0, y0),使|x0+y0|最小。

输入格式

共一行,三个整数a,b,c

输出格式

共一行,为|x0+y0|的最小值。
若无解输出“kito”。

样例

样例输入

1 1 1

样例输出

2 3 1

算法分析

  • 这个题求的是x + y 的最小值 我们可以直接枚举这个值
  • 设x + y == i 那么就有 x = i - y
    然后将这个代入原方程得 a \(\times\) i - a \(\times\) y + b \(\times\) y = c
    然后移项 估参可得 (b-a) \(\times\) y = c - a \(\times\) i
    因此就有y = \(\frac{c-a*i}{b-a}\)
  • 同理如果x + y == -i 一样可以求出一个y值
  • 我们知道C++中的除法是自动向下取整的 如果我们向下取整之后得到的x 与 y 仍然满足a\(\times\)x + b\(\times\)y == c
    那么就说明这一组解中x与y都为整数
  • 因为i是从小到大枚举的 找到符合的直接输出就好
  • 时间复杂度嘛 比较玄学……(答案多大我就循环多少次 O(答案)????)

Code



#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e8+10;
typedef long long ll;

int main(){
	ll a,b,c;scanf("%lld%lld%lld",&a,&b,&c);
	if(a == b){
		ll ans = c/a;
		if(ans * a == c)printf("%lld\n",ans);
		else printf("kito\n");
		return 0;
	}
	for(register int i = 0;i <= maxn;++i){
		ll y = (c - a*i)/(b - a);
		ll x = -y + i;
		if(x * a + y * b == c){
			printf("%d\n",i);
			return 0;
		}
		y = (c + a*i)/(b - a);
		x = -y - i;
		if(x * a + y * b == c){
			printf("%d\n",i);
			return 0;
		}
	}
	printf("kito\n");
	return 0;
}

T2最佳序列(暴力造他就完了)

题目大意

  • 你得到了一个N 个非负整数组成的序列A。
  • 我们称由序列A 的连续若干项组成的新序列为A 的一个连续子序列。给出两个正整数L,R(L <= R)。称A 的每一个长度不小于L 且不大于R 的连续子序列为一个纯洁序列,定义纯洁度为纯洁序列的所有元素的平均值。
  • 请你求出所有纯洁序列中的纯洁度的最大值。

输入格式

输入文件的第一行包括 3 个正整数 N,L,R。
第二行包括 N 个数,按顺序依次表示序列 A 的每一项。

输出格式

输出文件包括一行,一个实数,保留 4 位小数,表示答案。

样例

样例输入

3 2 3
6 2 8

样例输出

5.3333

算法分析

  • 直接暴力扫一遍就好
  • 先枚举长度然后枚举起点 注意前缀和优化一下就可以了
  • 或者可以维护一个滚动的窗口(或许是我太弱了吧 虽然复杂度一样 但是各种计算是比较多的 会比上边的算法慢辣么一丢丢就一丢丢)

Code

Code1



#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 20000+10;
ll a[maxn];
double ans;

int main(){
	int n,l,r;scanf("%d%d%d",&n,&l,&r);
	for(register int i = 1;i <= n;++i)scanf("%lld",&a[i]);
	for(register int d = l;d <= r;++d){
		ll now = 0;
		for(int i = 1;i <= d;++i)now += a[i];
		ll Max = now;
		int i = 1;
		int j = d;
		while(j <= n){
			i++,j++;
			now += a[j] - a[i-1];
			if(now > Max)Max = now;
		}
		if(1.0 * Max / d > ans)ans = 1.0 * Max / d;
	}
	printf("%.4lf\n",ans);
	return 0;
}

Code2

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 20000 + 10;
ll Max = 0;
ll a[maxn];
ll sum[maxn];
double ans;

int main(){
	int n,l,r;scanf("%d%d%d",&n,&l,&r);
	for(int i = 1;i <= n;++i)scanf("%lld",&a[i]);
	for(int i = 1;i <= n;++i)sum[i] = sum[i - 1] + a[i];
	for(int d = l;d <= r;++d){
		Max = 0;
		for(int i = 1,j;(j = i + d - 1) <= n;++i){
			if(sum[j] - sum[i-1] > Max)Max = sum[j] - sum[i-1];
		}
		if(ans < 1.0 * Max / d)ans = 1.0 * Max / d;
	}
	printf("%.4lf\n",ans);
	return 0;
}

T3周期串查询(哈希加线段树 或灵性做法)

题目大意

  • 有一个串只包含数字字符。串的长度为n,下标从1开始。
  • 有两种操作方式:
  • 1 l r c (1≤l≤r≤n, c是数字字符),表示将l到r这一段的字符全部改成c字符;
  • 2 l r d (1≤l≤r≤n, 1≤d≤r-l+1),表示询问l到r这一段区间内的子串是否是以d为周期的串。
  • 字符串s是以x (1≤x≤|s|),为周期的串的条件是:对于所有的 i从1到|s|-x, si = si + x 都成立。

输入格式

单组测试数据。

第一行有两个整数n, m ,k (1≤n≤10^5, 1≤m+k≤10^5),表示字符串长度和修改次数和询问次数。
第二行给出原始的串包含n位数字字符。
接下来m+k行,每行一个操作。
有两种形式:
1 l r с (1≤l≤r≤n, c是数字字符);
2 l r d (1≤l≤r≤n, 1≤d≤r-l+1)。

输出格式

对于每一个询问,如果该段子串是以d为周期的,输出YES,否则输出NO。

样例

样例输入

3 1 2
112
2 2 3 1
1 1 3 8
2 1 2 1

样例输出

NO
YES

算法分析

  • 线段树区间修改 区间查询 线段树的节点存子节点中最大值
  • 其实这个线段树主要是优化的作用 如果要求的这个区间中 最大值与最小值相等 那么肯定就是一样的 最后以d为周期查找一下就好
  • 关于瞎搞的话………… memset 与 memcpy

Code

Code1


// 比下面那种算法慢 但是很锻炼码力(自闭症患者慎入)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+10;
char s[maxn];
int v[maxn];
int cnt;
int cur[maxn];

struct node{
	int rt,l,r,Max,Min,lazy;
}a[maxn << 2];

void build(int rt,int l,int r){
	a[rt].l = l;a[rt].r = r;
	if(a[rt].l == a[rt].r){a[rt].Max = a[rt].Min = v[l];return;}
	int mid = l + r >> 1;
	build(rt << 1,l,mid);
	build(rt << 1 | 1,mid + 1,r);
	a[rt].Max = max(a[rt << 1].Max,a[rt << 1 | 1].Max);
	a[rt].Min = min(a[rt << 1].Min,a[rt << 1 | 1].Min);
}

void updata(int rt,int k){
	a[rt].Max = a[rt].Min = k;
	a[rt].lazy = k;
}

void pushdown(int rt){
	updata(rt << 1,a[rt].lazy);
	updata(rt << 1 | 1,a[rt].lazy);
	a[rt].lazy = 0;
}

void change(int rt,int l,int r,int k){
	if(a[rt].l >= l && a[rt].r <= r){
		a[rt].Max = a[rt].Min = k;
		a[rt].lazy = k;
		return;
	}
	if(a[rt].lazy)pushdown(rt);
	int mid = a[rt].l + a[rt].r >> 1;
	if(l <= mid)change(rt << 1,l,r,k);
	if(r > mid)change(rt << 1 | 1,l,r,k);
	a[rt].Max = max(a[rt << 1].Max,a[rt << 1 | 1].Max);
	a[rt].Min = min(a[rt << 1].Min,a[rt << 1 | 1].Min);
}

int askmax(int rt,int l,int r){
	if(a[rt].l >= l && a[rt].r <= r){
		if(a[rt].lazy)pushdown(rt);
		return a[rt].Max;
	}
	if(a[rt].lazy)pushdown(rt);
	int mid = a[rt].l + a[rt].r >> 1;
	if(r <= mid)return askmax(rt << 1,l,r);
	if(l > mid)return askmax(rt << 1 | 1,l,r);
	return max(askmax(rt << 1,l,r),askmax(rt << 1 | 1,l,r));
}

int askmin(int rt,int l,int r){
	if(a[rt].l >= l && a[rt].r <= r){
		if(a[rt].lazy)pushdown(rt);
		return a[rt].Min;
	}
	if(a[rt].lazy)pushdown(rt);
	int mid = a[rt].l + a[rt].r >> 1;
	if(r <= mid)return askmin(rt << 1,l,r);
	if(l > mid)return askmin(rt << 1 | 1,l,r);
	return min(askmin(rt << 1,l,r),askmin(rt << 1 | 1,l,r));
}

void first(int rt,int l,int r,int k){
	if(a[rt].lazy)pushdown(rt);
	if(a[rt].l == a[rt].r){cur[++cnt] = a[rt].Max;return;}
	int mid = a[rt].l + a[rt].r >> 1;
	if(l <= mid)first(rt << 1,l,r,k);
	if(r > mid)first(rt << 1 | 1,l,r,k);
}

bool check(int k){
	if(k > cnt)return 0;
	for(int i = 1;i <= cnt - k;++i)if(cur[i] != cur[i + k])return 0;
	return 1;
}

int main(){
	//freopen("Data.in","r",stdin);
	//freopen("c.out","w",stdout);
	int n,m,K;scanf("%d%d%d",&n,&m,&K);
	scanf("%s",s+1);
	for(int i = 1;i <= n;++i)v[i] = s[i] - '0';
	build(1,1,n);
	for(int i = 1;i <= m + K;++i){
		int flag,l,r,k;scanf("%d%d%d%d",&flag,&l,&r,&k);
		if(flag == 1)change(1,l,r,k);
		if(flag == 2){
			cnt = 0;
			first(1,l,r,k);
			if(askmax(1,l,r) == askmin(1,l,r)){
				printf("YES\n");
				continue;
			}
			if(check(k))printf("YES\n");
			else printf("NO\n");
		}
	}
	return 0;
}

Code2

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
char s[maxn];
int a[maxn],h[maxn];

int main(){
	int n,m,k;scanf("%d%d%d",&n,&m,&k);
	scanf("%s",s+1);
	k += m;
	while(k--){
		int flag,l,r,k;scanf("%d%d%d%d",&flag,&l,&r,&k);
		if(flag == 1)memset(s + l,k + '0',r - l + 1);
		if(flag == 2 && memcmp(s + l,s + l + k,r - l - k + 1))printf("NO\n");
		else if(flag == 2)printf("YES\n");
	}
	return 0;
}

T4追捕(送分题)

题目大意

  • Duan2baka:“jmsyzsfq天下第一蠢!”
  • jmsyzsfq:“你说什么?!”
  • 于是Duan2baka开始了逃亡的旅程,而jmsyzsfq也开始追捕Duan2baka。
  • 他们来到了一个有n个节点的有向图,迅速逃跑的Duan2baka会首先降落在有向图的某个节点T上,因为怕发出声音,他会永远静止不动。而随后跟来的jmsyzsfq会降落在图上随机一个节点S上(可以与T相同),并可以沿着图中的有向边随意走动。因为jmsyzsfq有着敏锐的嗅觉而且绝顶聪明,他一定会沿着正确的方向寻找Duan2baka。你可以认为,如果图中存在一条合法的从S到T的路径,那么jmsyzsfq一定会抓到Duan2baka——因此jmsyzsfq能否追捕到Duan2baka在他刚刚降落在图上的时候就已经确定了。现在请你帮帮jmsyzsfq,在他降落前告诉他有多大的概率能够追捕到Duan2baka,并告诉他想要追到Duan2baka他可以降落在哪些节点上。

输入格式

输入第一行包含三个整数n,m,opt,表示图中有n个节点,m条有向边;opt为0或1,含义见输出格式所述。

输入第2至m+1行每行两个整数u,v描述了图中一条从u到v的有向边。

输入第m+2行一个整数T表示Duan2baka降落的位置。

输出格式

如果输入的opt为0,只需要输出jmsyzsfq能够追捕到Duan2baka的概率。

如果输入的opt为1,输出两行,第一行输出jmsyzsfq能够追捕到Duan2baka的概率;第二行按从小到大输出想要追到Duan2baka他可以降落的节点编号,编号间用空格隔开。

对于jmsyzsfq能够追捕到Duan2baka的概率,是一个既约分数,形如“a/b”(a,b为整数),使gcd(a,b)=1,如果a=b,输出1/1。

样例

样例输入

9 10 1
1 2
2 1
2 4
6 1
9 6
6 5
5 3
3 7
3 1
1 8
1

样例输出

2/3
1 2 3 5 6 9 

算法分析

  • 就是dfs呗 把题好好看看就懂了 能到达这个点的点就相当于反向边这个点能到达的点
  • 把反向边建好直接dfs就好了

Code



#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
int cnt,head[maxn];
int vis[maxn];
int num;

struct node{
	int next,to;
}a[maxn];

void add(int x,int y){
	a[++cnt].to = y;
	a[cnt].next = head[x];
	head[x] = cnt;
}

int exgcd(int a,int b){return b ? exgcd(b,a % b) : a;}

void dfs(int s){
	vis[s] = 1;
	for(int i = head[s];i;i = a[i].next){
		int v = a[i].to;
		if(vis[v])continue;
		dfs(v);
		vis[v] = 1;
	}
}

int main(){
	int n,m,flag;scanf("%d%d%d",&n,&m,&flag);
	for(int i = 1;i <= m;++i){
		int x,y;scanf("%d%d",&x,&y);
		add(y,x);
	}
	int s;scanf("%d",&s);
	dfs(s);
	for(int i = 1;i <= n;++i){
		if(vis[i])num++;
	}
	int cjc = exgcd(n,num);
	printf("%d/%d\n",num/cjc,n/cjc);
	if(!flag)return 0;
	for(int i = 1;i <= n;++i){
		if(vis[i])printf("%d ",i);
	}
	return 0;
}

posted @ 2020-07-31 17:35  HISKrrr  阅读(195)  评论(2编辑  收藏  举报