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;
}