大集訓模擬賽十一
阿新 • • 發佈:2020-07-31
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\)
因此就有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;
}