1. 程式人生 > 實用技巧 >大假期集訓模擬賽11

大假期集訓模擬賽11

解方程

題目描述

解出一元二次方程 \(ax+by=c\) 的一組整數解 \((x0, y0)\) ,使 \(\left |x_0+y_0 \right |\) 最小。

輸入格式

共一行,三個整數 \(a\) , \(b\) , \(c\)

輸出格式

共一行,為 \(\left |x_0+y_0 \right |\) 的最小值。

若無解輸出 \(“kito”\)

樣例

樣例輸入 #1

1 1 1

樣例輸出 #1

1

樣例輸入 #2

2 3 1

樣例輸出 #2

0

資料範圍與提示

\(30\%\) 的資料,\(a,b\) 均為質數,\(c=1\)

另有 \(20\%\) 的資料,\(a,b,c\)

均為質數。

\(100\%\) 的資料,\(a,b,c\leq 1,000,000,000\)

思路

當時考試以為是個大數論,直接跳過,拿了特判 \(10opts\) 走人。

其實思路很簡單,\(x,y\) 只能是整數,推一下式子就行了。

\(\left |x_0+y_0 \right |=i\)

\(\therefore x=i-y\)\(x=-i-y\)

\(\therefore y=\frac {c\pm a*i} {b-a}\)

這樣只需列舉 \(i\) ,並判斷求出來的 \(y\) 是不是整數即可。

注意要特判一下 \(b==a\) ,不然會出錯。

程式碼

#include <bits/stdc++.h>
#define int long long 
using namespace std;

const int maxn=1e9+50;
inline int read(){
	int x=0,w=1;
	char ch;
	for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}

int a,b,c;

signed main(){
	a=read(),b=read(),c=read();
	if(c==0){//加這個會更快一丟丟
		printf("0\n");
		return 0;
	}
	if(a==b){//特判a==b
		if(c%a==0){
			printf("%lld\n",c/a);
		}else{
			printf("kito\n");
		}
		return 0;
	}
	for(int i=0;i<=maxn;i++){//列舉i
		if((c-a*i)%(b-a)==0){
			printf("%lld\n",i);
			return 0;
		}
		if((c+a*i)%(b-a)==0){
			printf("%lld\n",i);
			return 0;
		}
	}
	printf("kito\n");
	return 0;
}

最佳序列

題目描述

你得到了一個 \(N\) 個非負整陣列成的序列 \(A\)

我們稱由序列 \(A\) 的連續若干項組成的新序列為 \(A\) 的一個連續子序列。給出兩個正整數 \(L,R(L\leq R)\) 。稱 \(A\) 的每一個長度不小於 \(L\) 且不大於 \(R\) 的連續子序列為一個純潔序列,定義純潔度為純潔序列的所有元素的平均值。

請你求出所有純潔序列中的純潔度的最大值。

輸入格式

輸入檔案的第一行包括 \(3\) 個正整數 \(N,L,R\)

第二行包括 \(N\) 個數,按順序依次表示序列 \(A\) 的每一項。

輸出格式

輸出檔案包括一行,一個實數,保留 \(4\)

位小數,表示答案。

樣例

樣例輸入

3 2 3
6 2 8

樣例輸出

5.3333

資料範圍與提示

\(20\%\) 的資料滿足,\(1\leq N\leq 200\)

\(40\%\) 的資料滿足,\(1\leq N\leq 2,000\)

\(100\%\) 的資料滿足,\(1\leq N\leq 20,000\) , \(1\leq L\leq R\leq N\) , \(0\leq A_i\leq 1,000,000\)

思路

當時考試的時候想出了 \(3\) 種方法:

  • \(n^3\)的暴力,\(20,000\) 肯定會爆。

  • 在上面的基礎上用字首和優化一下,直接壓到 \(n^2\)

  • 用單調佇列來維護,二分查詢答案,直接壓倒 \(nlog_n\)但是我考試的時候寫炸了

程式碼

法二暴力

#include <bits/stdc++.h>
using namespace std;

const int maxn=2e4+50;
inline int read(){
	int x=0,w=1;
	char ch;
	for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}

int n,l,r;
int a[maxn],sum[maxn];
double ans;

int main(){
	n=read(),l=read(),r=read();
	for(register int i=1;i<=n;i++){
		a[i]=read();
		sum[i]=sum[i-1]+a[i];
	}
	for(register int d=l;d<=r;d++){//register優化一下
		int now=0;
		for(register int i=1,j;(j=i+d-1)<=n;i++){
			now=max(now,sum[j]-sum[i-1]);//除法會比較慢,所以求出和的最大,再進行除法,會很快
		}
		ans=max(ans,(double)now/d);		
	}
	printf("%.4lf\n",ans);
	return 0;
}

法三(借用一手大佬的碼)

#include <bits/stdc++.h>
using namespace std;

const int maxn=20000+10;

int l,r,n;
int a[maxn];
double tmp[maxn];
double sum[maxn];
int qu[maxn];
bool pd(double x){
	for(int i=1;i<=n;i++){
		tmp[i]=(double)a[i]-x;
		sum[i]=sum[i-1]+tmp[i];
	}
	int head=1,tail=0;
	int now=0;
	double ans=-1e9;
	for(int i=1;i<=n;i++){
		while(i-now>=l){
			while(head<=tail&&sum[qu[tail]]>=sum[now]){
				tail--;
			}
			qu[++tail]=now;
			now++;
		}
		while(head<=tail&&i-qu[head]>r){
			head++;
		}
		if(head<=tail){
			ans=max(ans,sum[i]-sum[qu[head]]);
		}
	}
	return ans>=0;
}
int main(){
	scanf("%d%d%d",&n,&l,&r);
	double fl=0,fr;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		fr=max(fr,(double)a[i]);
	}
	while(fr-fl>=1e-5){
		double mid=(fl+fr)/2;
		if(pd(mid)){
			fl=mid;
		}else{
			fr=mid;
		}
	}
	printf("%.4lf",(fl+fr)/2);
	return 0;
}

週期串查詢

題目描述

有一個串只包含數字字元。串的長度為 \(n\) ,下標從 \(1\) 開始。

有兩種操作方式:

\(1,l,r,c\) (\(1\leq l\leq r\leq n\) , \(c\) 是數字字元),表示將 \(l\)\(r\) 這一段的字元全部改成c字元;

\(2,l,r,d\) (\(1\leq l\leq r\leq n\) , \(1\leq d\leq r-l+1\)),表示詢問 \(l\)\(r\) 這一段區間內的子串是否是以d為週期的串。

字串 \(s\) 是以 \(x\) \((1\leq x\leq \left |s \right |)\) ,為週期的串的條件是:對於所有的 \(i\)\(1\)\(\left |s \right |-x\)\(s_i = s_i + x\) 都成立。

輸入格式

單組測試資料。

第一行有兩個整數\(n, m ,k (1\leq n\leq 10^5, 1\leq m+k\leq 10^5)\),表示字串長度和修改次數和詢問次數。

第二行給出原始的串包含 \(n\) 位數字字元。

接下來 \(m+k\) 行,每行一個操作。

有兩種形式:

\(1,l,r,с\) (\(1\leq l\leq r\leq n\) , \(c\) 是數字字元);

\(2,l,r,d\) (\(1\leq l\leq r\leq n\) , \(1\leq d\leq r-l+1\))。

輸出格式

對於每一個詢問,如果該段子串是以 \(d\) 為週期的,輸出 \(YES\) ,否則輸出 \(NO\)

樣例

樣例輸入

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

樣例輸出

NO
YES

資料範圍與提示

在這個樣例中第一個詢問的時候子串是“ \(12\) ”,他不是以 \(1\) 為週期的,所以答案是 \(NO\) 。第二個詢問的時候子串是“ \(88\) ”,是以 \(1\) 為週期的,所以答案是 \(YES\)

思路

\(hash\) 線段樹的老闆子了,但是 \(memset+memcmp\) 也能卡過,而且還不好卡,正解線段樹反而更慢。

程式碼

memset+memcmp

#include <bits/stdc++.h>
using namespace std;

const int maxn=1e5+50,INF=0x3f3f3f3f;
inline int read(){
	int x=0,w=1;
	char ch;
	for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}

int n,m,k;
char a[maxn];

int main(){
	n=read(),m=read(),k=read();
	scanf("%s",a+1);
	for(int i=1;i<=m+k;i++){
		int opt=read(),l=read(),r=read(),x=read();
		if(opt==1){
			memset(a+l,x+'0',r-l+1);
		}else{
			if(memcmp(a+l,a+l+x,r-l-x+1)){
				puts("NO");
			}else{
				puts("YES");
			}
		}
	}
	return 0;
}

hash

#include <bits/stdc++.h>
#define int unsigned long long 
using namespace std;

const int maxn=2e7+50,mod=1e9+9,base=17;

inline int read(){
	int x=0,w=1;
	char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}

int n,m;
char s[maxn];
int a[maxn],b[maxn];
struct Node{
	int l,r,lazy;
	int hash;
}node[maxn];
void Pushup(int x){
	node[x].hash=((node[x<<1].hash*a[node[x<<1|1].r-node[x<<1|1].l+1]+node[x<<1|1].hash)%mod+mod)%mod;
}

void Pushdown(int x){
	if(node[x].lazy+1){
		node[x<<1].lazy=node[x<<1|1].lazy=node[x].lazy;
		node[x<<1].hash=b[node[x<<1].r-node[x<<1].l]*node[x].lazy%mod;
		node[x<<1|1].hash=b[node[x<<1|1].r-node[x<<1|1].l]*node[x].lazy%mod;
		node[x].lazy=-1;
	}
	return;
}

void Build(int rt,int l,int r){
	node[rt].l=l;
	node[rt].r=r;
	node[rt].lazy=-1;
	if(l==r){
		node[rt].hash=s[l]-'0'+1;
		return;
	}
	int mid=(node[rt].l+node[rt].r)>>1;
	Build(rt<<1,l,mid);
	Build(rt<<1|1,mid+1,r);
	Pushup(rt);
}

void Add(int rt,int l,int r,int w){
	if(node[rt].l==l&&node[rt].r==r){
		node[rt].lazy=w;
		node[rt].hash=b[node[rt].r-node[rt].l]*w%mod;
		return;
	}
	Pushdown(rt);
	int mid=(node[rt].l+node[rt].r)>>1;
	if(mid>=r){
		Add(rt<<1,l,r,w);
	}else if(l>mid){
		Add(rt<<1|1,l,r,w);
	}else{
		Add(rt<<1,l,mid,w);
		Add(rt<<1|1,mid+1,r,w);
	}
	Pushup(rt);
}
int Query(int rt,int l,int r){
	if(l>r)return 0;
	if(node[rt].l==l&&node[rt].r==r){
		return node[rt].hash;
	}
	Pushdown(rt);
	int mid=(node[rt].l+node[rt].r)>>1;
	if(mid>=r){
		return Query(rt<<1,l,r);
	}else if(mid<l){
		return Query(rt<<1|1,l,r);
	}else {
		return (Query(rt<<1,l,mid)*a[r-mid]+Query(rt<<1|1,mid+1,r))%mod;
	}
}

signed main(){
	n=read();m=read();
	scanf("%s",s+1);
	a[0]=1;
	b[0]=1;
	for(int i=1;i<=n;i++){
		a[i]=a[i-1]*base%mod;
		b[i]=(b[i-1]*base+1)%mod;
	}
	Build(1,1,n);
	while(m--){
		int pd=read(),l=read(),r=read(),x=read();
		if(pd==1){
			Add(1,l,r,x+1);
		}else{
			if(Query(1,l,r-x)==Query(1,l+x,r)){
				printf("YES\n");
			}else{
				printf("NO\n");
			}
		}
	}
	return 0;
}

追捕

題目描述

\(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\)

樣例

樣例輸入 #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

樣例輸出 #1

2/3
1 2 3 5 6 9 

樣例 #1解釋

圖中共 \(9\) 個節點,能夠到達節點 \(S=1\) 的節點共 \(6\) 個:\({1,2,3,5,6,9}\) 。所以能夠追捕到 \(Duan2baka\) 的概率為 \(6/9=2/3\)

樣例輸入 #2

5 7 1
1 2
1 3
1 5
2 4
4 1
4 5
5 3
1

樣例輸出 #2

3/5
1 2 4

資料範圍與提示

\(opt=0\)\(opt=1\) 的資料各 \(50\%\)

對於 \(opt=0\)\(opt=1\) 的情況,有著完全相同的子任務:

對於 \(10\%\) 的資料,\(n,m\leq 100\)

對於另外 \(30\%\) 的資料,\(n,m\leq 100,000\)

對於另外 \(10%\) 的資料,保證圖是一個完全圖,即對於任意兩個點 \(u\)\(v\) ,必然有兩條有向邊 \(u→v\)\(v→u\)

對於另外 \(20\%\) 的資料,保證圖是一個有向無環圖,即對於任意一個點 \(x\) ,不存在圖上一條路徑從 \(x\) 經過其它點後回到 \(x\)

對於另外 \(20%\) 的資料,保證如果圖上存在一條邊 \(u→v\) ,一定存在一條邊 \(v→u\)

對於 \(100\%\) 的資料,\(n,m\leq 1,000,000\) ,保證資料合法且不存在重邊、自環。

思路

裸的 \(DFS\) ,根本沒有思路可言,反向建邊,反向跑一遍 \(DFS\)這不是有手就行???

程式碼

#include <bits/stdc++.h>
using namespace std;

const int maxn=1e6+50,INF=0x3f3f3f3f;
inline int read(){
	int x=0,w=1;
	char ch;
	for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}

int n,m,opt,s;
int ans;
int vis[maxn];
int path[maxn];

struct Edge{
	int to,next;
}e[maxn];

int GCD(int a,int b){
	return b==0 ? a : GCD(b,a%b);
}

int tot,head[maxn];
void Add(int u,int v){
	e[++tot].to=v;
	e[tot].next=head[u];
	head[u]=tot;
}

void DFS(int u){
	vis[u]=1;
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(vis[v])continue;
		vis[v]=1;
		DFS(v);
	}
}

int main(){
	n=read(),m=read(),opt=read();
	for(register int i=1;i<=m;i++){
		int u=read(),v=read();
		Add(v,u);//反向建邊
	}
	s=read();
	DFS(s);//從終點往其他方向跑
	for(int i=1;i<=n;i++){
		if(vis[i]){
			path[++ans]=i;
		}	
	}
	int chu=GCD(ans,n);
	if(chu!=1){
		printf("%d/%d",ans/chu,n/chu);
	}else{
		printf("%d/%d",ans,n);
	}
	if(opt==1){
		printf("\n");
		for(register int i=1;i<=ans;i++){
			printf("%d ",path[i]);
		}
		printf("\n");
	}
	return 0;
}

不等式

題目描述

\(z\) 熱衷於數學。

今天數學課的內容是解不等式: \(L\leq S\times x\leq R\)

小z心想這也太簡單了,不禁陷入了深深的思考:假如已知 \(L,R,S,M\) ,滿足 \(L\leq (S\times x)mod M\leq R\) 的最小正整數該怎麼求呢?

輸入格式

第一行包含一個整數 \(T\) ,表示資料組數,接下來是 \(T\) 行,每行為四個正整數 \(M,S,L,R\)

輸出格式

對於每組資料,輸出滿足要求的 \(x\) 值,若不存在,輸出 \(-1\)

樣例

樣例輸入

1
5 4 2 3

樣例輸出

2

資料範圍與提示

\(30\%\) 的資料中保證有解並且答案小於等於 \(10^6\)

另外 \(20\%\) 的資料中保證 \(L=R\)

\(100\%\) 的資料中 \(T\leq 100,M,S,L,R\leq 10^9\)

思路

待更新~~~~~~~~~