• 大集训模拟赛十一


    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 ( imes) i - a ( imes) y + b ( imes) y = c
      然后移项 估参可得 (b-a) ( imes) y = c - a ( imes) i
      因此就有y = (frac{c-a*i}{b-a})
    • 同理如果x + y == -i 一样可以求出一个y值
    • 我们知道C++中的除法是自动向下取整的 如果我们向下取整之后得到的x 与 y 仍然满足a( imes)x + b( imes)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
    ",ans);
    		else printf("kito
    ");
    		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
    ",i);
    			return 0;
    		}
    		y = (c + a*i)/(b - a);
    		x = -y - i;
    		if(x * a + y * b == c){
    			printf("%d
    ",i);
    			return 0;
    		}
    	}
    	printf("kito
    ");
    	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
    ",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
    ",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
    ");
    				continue;
    			}
    			if(check(k))printf("YES
    ");
    			else printf("NO
    ");
    		}
    	}
    	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
    ");
    		else if(flag == 2)printf("YES
    ");
    	}
    	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
    ",num/cjc,n/cjc);
    	if(!flag)return 0;
    	for(int i = 1;i <= n;++i){
    		if(vis[i])printf("%d ",i);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    202103226-1 编程作业
    阅读任务
    1 20210309-1 准备工作
    20210405-1 案例分析作业
    第一周作业
    20210309-2 阅读任务
    20210309-1 准备工作
    编程作业
    阅读任务
    准备工作
  • 原文地址:https://www.cnblogs.com/2004-08-20/p/13411044.html
Copyright © 2020-2023  润新知