XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Siberia

Claris發表於2018-03-22

1. GUI

按題意判斷即可。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 0, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
bool inclu(int L, int R, int l, int r)
{
	return L <= l && r <= R;
}
int main()
{
	scanf("%d", &casenum);
	for (casei = 1; casei <= casenum; ++casei)
	{
		int x1, x2, x3, x4;
		int y1, y2, y3, y4;
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		scanf("%d%d%d%d",&x3,&y3,&x4,&y4);
		if(inclu(x1,x2,x3,x4) && inclu(y1,y2,y3,y4))
		{
			puts("B in A");
		}
		else if(inclu(x3,x4,x1,x2) && inclu(y3,y4,y1,y2))
		{
			puts("A in B");
		}
		else if((x2 < x3 || x4 < x1) || (y2 < y3 || y4 < y1))
		{
			puts("Separate");
		}
		else puts("Intersect");
	}
	return 0;
}
/*
【trick&&吐槽】


【題意】


【分析】


【時間複雜度&&優化】


*/

  

2. Searching on the Cube

首先爬山找到一個極小點,然後不斷前進找到另一個極小點,分析哪一個是答案即可。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 0, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n;
char rtn[100];
void fwd()
{
	puts("forward");
	fflush(stdout);
	scanf("%s", rtn);
}
void rgt()
{
	puts("right");
	fflush(stdout);
}
void lft()
{
	puts("left");
	fflush(stdout);
}
void dig()
{
	puts("dig");
	fflush(stdout);
	exit(0);
}
bool BEST()
{
	fwd();
	if(strcmp(rtn, "closer") == 0)
	{
		return 0;
	}
	lft(); lft(); fwd();
	fwd();
	if(strcmp(rtn, "closer") == 0)
	{
		return 0;
	}
	lft(); lft(); fwd();
	lft(); fwd();
	if(strcmp(rtn, "closer") == 0)
	{
		return 0;
	}
	lft(); lft(); fwd();
	fwd();
	if(strcmp(rtn, "closer") == 0)
	{
		return 0;
	}
	lft(); lft(); fwd();
	return 1;
}
bool onlycheckBEST()
{
	bool flag = 1;
	fwd();
	if(strcmp(rtn, "closer") == 0)
	{
		flag = 0;
	}
	lft(); lft(); fwd(); lft(); lft();
	if(!flag)return 0;
	
	lft(); fwd();
	if(strcmp(rtn, "closer") == 0)
	{
		flag = 0;
	}
	lft(); lft(); fwd(); lft();
	if(!flag)return 0;
	
	rgt(); fwd();
	if(strcmp(rtn, "closer") == 0)
	{
		flag = 0;
	}
	lft(); lft(); fwd(); rgt();
	if(!flag)return 0;
	
	lft(); lft(); fwd();
	if(strcmp(rtn, "closer") == 0)
	{
		flag = 0;
	}
	lft(); lft(); fwd();
	if(!flag)return 0;
	return 1;
}
int main()
{
	while(!BEST());
	int clo = 0;
	int far = 0;
	while(1)
	{
		fwd();
		if(strcmp(rtn, "closer") == 0)
		{
			++clo;
		}
		else if(strcmp(rtn, "farther") == 0)
		{
			++far;
		}
		if(onlycheckBEST())
		{
			if(clo >= far)
			{
				dig();
			}
			else clo = far = 0;
		}
	}
	return 0;
}

/*
【trick&&吐槽】


【題意】


【分析】


【時間複雜度&&優化】


*/

  

3. Mirrors

留坑。

 

4. Roads to cinematography

$1$和$n$的最優連法一定是$1$往下,$n$往左,中間必然存在一個點$i$滿足$i$往左到$1$,$i+1$往下到$n$。

設$f[l][r]$表示$l$往下,$r$往左時,$[l,r]$的最優連法,列舉$i$轉移即可。

時間複雜度$O(n^3)$。

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=505,inf=1000000000;
int n,i,j,m,e[100010][4];
int f[N][N],g[N][N];bool v[N][N];
struct P{int x,y;}a[N];
inline void add(int x1,int y1,int x2,int y2){
	if(x1<x2)swap(x1,x2),swap(y1,y2);
	if(y1<y2)swap(x1,x2),swap(y1,y2);
	if(x1==x2&&y1==y2)return;
	m++;
	e[m][0]=x1;
	e[m][1]=y1;
	e[m][2]=x2;
	e[m][3]=y2;
}
void dfs(int l,int r){
	if(l+1>=r)return;
	if(v[l][r])return;
	v[l][r]=1;
	f[l][r]=inf;
	for(int i=l;i<r;i++){
		//i left,i+1 down
		dfs(l,i);
		dfs(i+1,r);
		int t=f[l][i]+f[i+1][r]+a[i].x-a[l].x+a[i+1].y-a[r].y;
		if(t<f[l][r]){
			f[l][r]=t;
			g[l][r]=i;
		}
	}
}
void go(int l,int r){
	if(l+1>=r)return;
	int i=g[l][r];
	go(l,i);
	go(i+1,r);
	add(a[l].x,a[i].y,a[i].x,a[i].y);
	add(a[i+1].x,a[r].y,a[i+1].x,a[i+1].y);
}
int main(){
	scanf("%d",&n);
	for(i=1;i<=n;i++)scanf("%d%d",&a[i].x,&a[i].y);
	dfs(1,n);
	f[1][n]+=a[1].x+a[1].y+a[n].x-a[1].x;
	add(0,0,a[1].x,0);
	add(a[1].x,0,a[1].x,a[1].y);
	add(a[1].x,a[n].y,a[n].x,a[n].y);
	go(1,n);
	printf("%d %d\n",m,f[1][n]);
	for(i=1;i<=m;i++){for(j=0;j<4;j++)printf("%d ",e[i][j]);puts("");}
}

  

5. Geometric solver

按題意模擬。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() {  }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 2e5 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n, m;
int id[N];
int root[N];
int col[N];
bool edge[N];
vector<int>ans;
bool FLAG;
struct A
{
	int y;
	int tp;
	int id;
};
vector< A >a[N];
void dfs(int x)
{
	for(auto it : a[x])
	{
		int y = it.y;
		int tp = it.tp;
		int id = it.id;
		if(col[y] == -1)
		{
			col[y] = col[x] ^ tp;
			edge[id] = 1;
			dfs(y);
		}
		else
		{
			if(!edge[id])
			{
				edge[id] = 1;
				ans.push_back(it.id);
				//printf("!edge[id]: %d\n", id);
			}
			if(col[y] != (col[x] ^ tp))
			{
				FLAG = 0;
			}
		}
	}
}
int main()
{
	while(~scanf("%d%d",&n, &m))
	{
		MS(edge, 0);
		MS(root, -1);
		MS(id, -1);
		ans.clear();
		for(int i = 1; i <= n; ++i)
		{
			a[i].clear();
		}
		FLAG = 1;
		for(int i = 1; i <= m; ++i)
		{
			char op[100];
			scanf("%s", op);
			if(op[0] == 'v')
			{
				int x; scanf("%d", &x);
				if(root[x] == 0)
				{
					ans.push_back(i);
					//printf("root[x] == 0: %d\n", i);
				}
				else if(root[x] == 1)
				{
					FLAG = 0;
				}
				else
				{
					root[x] = 0;
					id[x] = i;
				}
			}
			else if(op[0] == 'h')
			{
				int x; scanf("%d", &x);
				if(root[x] == 1)
				{
					ans.push_back(i);
					//printf("root[x] == 1: %d\n", i);
				}
				else if(root[x] == 0)
				{
					FLAG = 0;
				}
				else
				{
					root[x] = 1;
					id[x] = i;
				}
			}
			else 
			{
				int x, y;
				scanf("%d%d", &x, &y);
				if(op[1] == 'e')//be horizontal
				{
					a[x].push_back({y, 1, i});	
					a[y].push_back({x, 1, i});
				}
				else
				{
					a[x].push_back({y, 0, i});
					a[y].push_back({x, 0, i});
				}
			}
		}
		MS(col, -1);
		int useful = 0;
		for(int i = 1; i <= n; ++i)
		{
			if(root[i] != -1)
			{
				if(col[i] == -1)
				{
					col[i] = root[i];
					dfs(i);
					++useful;
				}
				else
				{
					if(col[i] != root[i])
					{
						FLAG = 0;
					}
					ans.push_back(id[i]);
					//printf("same_con: %d\n", id[i]);
				}
			}
		}
		for(int i = 1; i <= n; ++i)
		{
			if(col[i] == -1)
			{
				col[i] = 0;
				dfs(i);
			}
		}
		if(!FLAG)
		{
			puts("inconsistent");
		}
		else
		{
			puts("consistent");
			printf("%d\n", ans.size());
			int sz = ans.size();
			for(int i = 0; i < sz; ++i)
			{
				printf("%d%c", ans[i], i == sz - 1 ? '\n' : ' ');
			}		
		}
	}
	return 0;
}

/*
【trick&&吐槽】


【題意】


【分析】


【時間複雜度&&優化】


*/

  

6. Monsters

設$f[i]=\max(f[i-1],s[i])$,則$ans=\prod\min(m[i],f[i])$。

線段樹維護每個區間$[l,r]$內只考慮區間$[l,r]$時以下資訊:

  • $fl,fr$:$f[l]$和$f[r]$的值。
  • $mul$:$\prod\min(m[i],f[i])$。
  • $rmul$:將右兒子用左兒子的$f$修正後右兒子的貢獻。

對於$mul$,有$mul=左兒子的mul\times ask(右兒子,左兒子的f[r])$。

其中$ask(x,pre)$表示考慮$x$的子樹,之前$f$為$pre$時的乘積:

  • 若$fl\geq pre$,則無需修正,直接返回$mul$即可。
  • 若$x$為葉子,則暴力處理即可。
  • 若左兒子的$fr\geq pre$,則右兒子只會被左兒子修正,返回$ask(左兒子,pre)\times rmul$即可。
  • 否則左兒子將全部被修正為$pre$,故返回$ask(右兒子,pre)\times 左兒子全部修正為pre$的貢獻即可。而貢獻可以在每個節點套上一棵Treap來$O(\log n)$計算。

總時間複雜度$O(n\log^3n)$。

#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int N=100010,M=262150,P=1000000007;
int fl[M],fr[M],mul[M],rmul[M];
int n,_,i,s[N],m[N];
int CNT,MUL,ni;
struct node{
	int val,cnt,sum,v,mul,p;
	node*l,*r;
	node(){
		val=cnt=sum=p=0;
		v=mul=1;
		l=r=NULL;
	}
	void up(){
		sum=cnt+l->sum+r->sum;
		mul=1LL*v*l->mul%P*r->mul%P;
	}
}*blank=new(node),*T[M],pool[5000000],*cur=pool;
inline void Rotl(node*&x){node*y=x->r;x->r=y->l;x->up();y->l=x;y->up();x=y;}
inline void Rotr(node*&x){node*y=x->l;x->l=y->r;x->up();y->r=x;y->up();x=y;}
void Ins(node*&x,int p){
	if(x==blank){
		x=cur++;
		x->val=p;
		x->l=x->r=blank;
		x->cnt=x->sum=1;
		x->v=x->mul=p;
		x->p=rand();
		return;
	}
	x->sum++;
	x->mul=1LL*x->mul*p%P;
	if(p==x->val){
		x->cnt++;
		x->v=1LL*x->v*p%P;
		return;
	}
	if(p<x->val){
		Ins(x->l,p);
		if(x->l->p>x->p)Rotr(x);
	}else{
		Ins(x->r,p);
		if(x->r->p>x->p)Rotl(x);
	}
}
void Del(node*&x,int p,int q){
	x->sum--;
	x->mul=1LL*x->mul*q%P;
	if(p==x->val){
		x->cnt--;
		x->v=1LL*x->v*q%P;
		return;
	}
	if(p<x->val){
		Del(x->l,p,q);
		if(x->l->p>x->p)Rotr(x);
	}else{
		Del(x->r,p,q);
		if(x->r->p>x->p)Rotl(x);
	}
}
void Ask(node*&x,int p){//<p
	if(x==blank)return;
	if(p==x->val){
		CNT+=x->l->sum;
		MUL=1LL*MUL*x->l->mul%P;
		return;
	}
	if(p<x->val){
		Ask(x->l,p);
		return;
	}
	Ask(x->r,p);
	CNT+=x->l->sum+x->cnt;
	MUL=1LL*MUL*x->l->mul%P*x->v%P;
}
inline int po(int a,int b){
	int t=1;
	for(;b;b>>=1,a=1LL*a*a%P)if(b&1)t=1LL*t*a%P;
	return t;
}
void build(int x,int a,int b){
	if(a<b){
		int mid=(a+b)>>1;
		build(x<<1,a,mid);
		build(x<<1|1,mid+1,b);
	}
	int i;
	fl[x]=fr[x]=s[a];
	mul[x]=1;
	T[x]=blank;
	for(i=a;i<=b;i++){
		fr[x]=max(fr[x],s[i]);
		mul[x]=1LL*mul[x]*min(fr[x],m[i])%P;
		Ins(T[x],m[i]);
	}
	if(a<b)rmul[x]=1LL*mul[x]*po(mul[x<<1],P-2)%P;
}
inline int query(int x,int a,int b,int pre){
	CNT=0;
	MUL=1;
	Ask(T[x],pre);
	return 1LL*MUL*po(pre,b-a+1-CNT)%P;
	//int t=1;
	//for(int i=a;i<=b;i++)t=1LL*t*min(m[i],pre)%P;
	//return t;
}
int ask(int x,int a,int b,int pre){
	if(fl[x]>=pre)return mul[x];
	if(a==b)return min(m[a],pre);
	int mid=(a+b)>>1;
	if(fr[x<<1]>=pre)return 1LL*ask(x<<1,a,mid,pre)*rmul[x]%P;
	return 1LL*query(x<<1,a,mid,pre)*ask(x<<1|1,mid+1,b,pre)%P;
}
inline void up(int x,int a,int b){
	fl[x]=fl[x<<1];
	fr[x]=max(fr[x<<1],fr[x<<1|1]);
	int mid=(a+b)>>1;
	mul[x]=1LL*mul[x<<1]*ask(x<<1|1,mid+1,b,fr[x<<1])%P;
	rmul[x]=1LL*mul[x]*po(mul[x<<1],P-2)%P;
}
void change(int x,int a,int b,int c){
	if(a==b){
		fl[x]=fr[x]=s[a];
		mul[x]=min(s[a],m[a]);
		return;
	}
	int mid=(a+b)>>1;
	if(c<=mid)change(x<<1,a,mid,c);else change(x<<1|1,mid+1,b,c);
	up(x,a,b);
}
void changem(int x,int a,int b,int c,int A,int B){
	Ins(T[x],B);
	Del(T[x],A,ni);
	if(a==b)return;
	int mid=(a+b)>>1;
	if(c<=mid)changem(x<<1,a,mid,c,A,B);else changem(x<<1|1,mid+1,b,c,A,B);
}
int main(){
	blank->l=blank->r=blank;
	scanf("%d%d%d",&n,&_,&s[1]);
	for(i=1;i<=n;i++)scanf("%d",&m[i]);
	for(i=2;i<=n+1;i++)scanf("%d",&s[i]);
	build(1,1,n);
	//shutaoshu
	printf("%d\n",mul[1]);
	while(_--){
		int op,x,y;
		scanf("%d%d%d",&op,&x,&y);
		if(op==0){
			ni=po(m[x],P-2);
			changem(1,1,n,x,m[x],y);
			m[x]=y;
			change(1,1,n,x);
		}else{
			x++;
			if(x<=n){
				s[x]=y;
				change(1,1,n,x);
			}
		}
		printf("%d\n",mul[1]);
	}
}

  

7. Regular expressions

注意到$((a(c|(g|t)))*)$可以匹配所有字串,所以答案不超過$16$。

爆搜出所有短正規表示式後,建立DFA,最小化DFA判斷即可。

 

8. WSO-2017 soccer team

假設所有人都選擇$2a[i]$,那麼需要選出$k=\frac{r-l+1}{3}$個人增加$2(d[i]-a[i])$,還需要再選出$k$個人增加$d[i]-a[i]$,故可持久化線段樹維護區間$k$小值即可。

時間複雜度$O(n\log n)$。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=129000,M=N*21;
int n,m,i,x,y;
ll a[N],d[N],sa[N],c[N];
int T[N],tot,l[M],r[M],cnt[M];ll sum[M];
int ins(int x,int a,int b,int c,ll p){
	int y=++tot;
	cnt[y]=cnt[x]+1;
	sum[y]=sum[x]+p;
	if(a==b)return y;
	int mid=(a+b)>>1;
	if(c<=mid)l[y]=ins(l[x],a,mid,c,p),r[y]=r[x];
	else l[y]=l[x],r[y]=ins(r[x],mid+1,b,c,p);
	return y;
}
inline ll kth(int x,int y,int k){
	if(!k)return 0;
	int a=1,b=n,mid;ll ans=0;
	while(a<b){
		mid=(a+b)>>1;
		int t=cnt[l[x]]-cnt[l[y]];
		if(t>=k){
			b=mid;
			x=l[x];
			y=l[y];
		}else{
			k-=t;
			ans+=sum[l[x]]-sum[l[y]];
			a=mid+1;
			x=r[x];
			y=r[y];
		}
	}
	if(k)ans+=(sum[x]-sum[y])/(cnt[x]-cnt[y])*k;
	return ans;
}
inline ll ask(int x,int y,int l,int r){return kth(x,y,r)-kth(x,y,l-1);}
int main(){
	scanf("%d",&n);
	for(i=1;i<=n;i++)scanf("%lld",&a[i]),sa[i]=sa[i-1]+a[i];
	for(i=1;i<=n;i++)scanf("%lld",&d[i]);
	for(i=1;i<=n;i++)c[i]=d[i]-a[i];
	sort(c+1,c+n+1);
	for(i=1;i<=n;i++)T[i]=ins(T[i-1],1,n,lower_bound(c+1,c+n+1,d[i]-a[i])-c,d[i]-a[i]);
	scanf("%d",&m);
	while(m--){
		scanf("%d%d",&x,&y);
		ll ans=(sa[y]-sa[x-1])*2;
		int len=(y-x+1)/3;
		ans+=ask(T[y],T[x-1],len*2+1,len*3)*2;
		ans+=ask(T[y],T[x-1],len+1,len*2);
		printf("%lld.%lld\n",ans/2,ans%2*5);
	}
}

  

9. Primitive divisors

列舉所有的質數$p$,滿足$q^n\bmod p=1$的$p$不會很多,對於每個將$\varphi(p)$分解質因數找到最小迴圈節判斷即可。

#include<cstdio>
const int N=10000000;
int n,q,tot,i,j,p[N],ans[N],fin,v[N];
inline int po(int a,int b,int P){
	int t=1;
	for(;b;b>>=1,a=1LL*a*a%P)if(b&1)t=1LL*t*a%P;
	return t;
}
inline bool check(int x){
	if(x<=n)return 0;
	if(po(q,n,x)!=1)return 0;
	int per=x-1;
	int t=per;
	while(t>1){
		int o=v[t];
		if(po(q,per/o,x)==1)per/=o;
		if(n>per)return 0;
		t/=o;
	}
	return 1;
}
int main(){
	scanf("%d%d",&q,&n);
	for(i=2;i<N;i++){
		if(!v[i]){
			p[tot++]=i;
			v[i]=i;
		}
		for(j=0;j<tot&&1LL*i*p[j]<N;j++){
			v[i*p[j]]=p[j];
			if(i%p[j]==0)break;
		}
	}
	for(i=0;i<tot;i++)if(check(p[i]))ans[++fin]=p[i];
	printf("%d\n",fin);
	for(i=1;i<=fin;i++)printf("%d ",ans[i]);
}

  

10. Tickets

按題意模擬。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() {  }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 1e6 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n;
char a[N], b[N];
int main()
{
	while(~scanf("%s%s",a,b))
	{
		int n = strlen(a);
		int A = 0, B = 0;
		for(int i = 0; i < n; ++i)
		{
			if(a[i] < b[i])++A;
			else if(a[i] > b[i])++B;
		}
		printf("%d\n%d\n",A,B);
	}
	return 0;
}

/*
【trick&&吐槽】


【題意】


【分析】


【時間複雜度&&優化】


*/

  

11. Logarithm smoothing

二分答案$mid$,將$f(x)=c\ln x$的影象往上下分別平移$mid$。

從$(a,f(a)+mid)$開始往右沿著切線走,判斷走$n$步是否可以到達$b$之後的位置即可。

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long double ld;
const int T=50;
int n;ld C,A,B,OFFSET;
void read(ld&x){
	double t;
	scanf("%lf",&t);
	x=t;
}
void write(ld x){
	printf("%.15f",(double)x);
}
bool down(ld A,ld B,int n);
bool up(ld A,ld B,int n){
	//printf("up %d\n",n);
	if(A>=B)return 1;
	if(n<1)return 0;
	ld y=C*log(A)+OFFSET;
	//f'(x)=C/x
	ld L=A,R=B+10;
	for(int i=0;i<T;i++){
		ld mid=(L+R)/2;
		if((C*log(mid)-OFFSET-y)/(mid-A)<C/mid)L=mid;else R=mid;
	}
	return down(L,B,n);
}
bool down(ld A,ld B,int n){
	//printf("down %d\n",n);
	if(A>=B)return 1;
	if(n<1)return 0;
	ld y=C*log(A)-OFFSET;
	//f'(x)=C/x
	ld k=C/A;
	ld L=A,R=B+10;
	for(int i=0;i<T;i++){
		ld mid=(L+R)/2;
		if(y+(mid-A)*k<C*log(mid)+OFFSET)L=mid;else R=mid;
	}
	return up(L,B,n-1);
}
bool check(ld _mid){
	OFFSET=_mid;
	if(down(A,B,n))return 1;
	if(up(A,B,n))return 1;
	return 0;
}
int main(){
	int Case;
	scanf("%d",&Case);
	while(Case--){
		scanf("%d",&n);
		read(C);
		read(A);
		read(B);
		ld l=0,r=C*(log(B)-log(A))/2;
		for(int i=0;i<100;i++){
			ld mid=(l+r)/2;
			if(check(mid))r=mid;else l=mid;
		}
		write(l);
		puts("");
	}
}

  

12. Outer space signals

KMP求出兩個串最左和最右出現位置然後判斷即可。

時間複雜度$O(n)$。

#include<cstdio>
#include<cstring>
const int N=1000010;
int Case,na,nb,nc,i,bl,br,cl,cr;char a[N],b[N],c[N];
int nxt[N];
void solve(int n,char*a,int m,char*b,int&l,int&r){
  int i,j;
  for(nxt[1]=j=0,i=2;i<=n;nxt[i++]=j){
    while(j&&a[j+1]!=a[i])j=nxt[j];
    if(a[j+1]==a[i])j++;
  }
  l=r=0;
  for(i=1,j=0;i<=m;i++){
    while(j&&a[j+1]!=b[i])j=nxt[j];
    if(a[j+1]==b[i])j++;
    if(j==n){
      if(!l)l=i;
      r=i;
      j=nxt[j];
    }
  }
}
bool check(){
  if(!bl||!cl)return 0;
  if(cr-nc+1>bl)return 1;
  if(br-nb+1>cl)return 1;
  return 0;
}
int main(){
  scanf("%d",&Case);
  while(Case--){ 
    scanf("%s%s%s",a+1,b+1,c+1);
    na=strlen(a+1);
    nb=strlen(b+1);
    nc=strlen(c+1);
    solve(nb,b,na,a,bl,br);
    solve(nc,c,na,a,cl,cr);
    puts(check()?"YES":"NO");
  }
}

  

相關文章