Codeforces Beta Round #7 题解

91 阅读2分钟

比赛链接

A B

C

思路

CC移项,转化成求Ax+By=CAx+By=-C的整数解。扩展欧几里得。
d=gcd(a,b)d=gcd(a,b),扩展欧几里得可以求得一组整数解(x0,y0)(x_0,y_0),满足Ax0+By0=gAx_0+By_0=g

Ax0d+By0d=1Ax0(C)d+By0(C)d=C\frac{Ax_0}{d}+\frac{By_0}{d}=1\\\\ \frac{Ax_0\cdot (-C)}{d}+\frac{By_0\cdot (-C)}{d}=-C\\

根据贝祖定理,若存在两个整数x1,y1x_1,y_1满足Ax1+By1=CAx_1+By_1=-C,那么必定有(C)d(-C)\mid d。因此特判若(C)%d0(-C)\%d\neq 0,输出1-1。否则解就是(x0Cd,y0Cd)(x_0\cdot \frac{-C}{d},y_0\cdot \frac{-C}{d})

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(ll (i)=(st);(i)<=(ed);++(i))
#define bl(u,i) for(ll (i)=head[(u)];(i);(i)=e[(i)].nxt)
#define sf(a) scanf("%lld",&(a));
#define pf(a) prllf("%lld\n",(a));
#define pii pair<ll,ll> 
typedef long long ll;
using namespace std;
ll a,b,c;
ll e_gcd(ll a,ll b,ll &x,ll &y){
	if(!b){
		x=1;y=0;
		return a;
	}
	ll gcd=e_gcd(b,a%b,y,x);
	y-=a/b*x;
	return gcd;
}
int main()
{
	cin>>a>>b>>c;
	ll x,y;
	ll g=e_gcd(a,b,x,y);
	if(c%g!=0)
	{
		cout<<-1<<endl;
		return 0;
	}
	cout<<x*(-c)/g<<" "<<y*(-c)/g<<endl;
}

D

思路

Manacher算法O(n)O(n)预处理得到每个字符的回文半径,就可以O(1)O(1)判断任意子串是否为回文串。记f[i]f[i]为子字符串1i1\dots i的阶数,若1i1\dots i为回文串,则f[i]=f[i/2]+1f[i]=f[i/2]+1。按顺序维护即可。总复杂度O(n)O(n)

  • scanf输入字符串居然比getchar快400ms
  • int居然比long long快120ms

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(ll (i)=(st);(i)<=(ed);++(i))
#define bl(u,i) for(ll (i)=head[(u)];(i);(i)=e[(i)].nxt)
#define sf(a) scanf("%lld",&(a));
#define pf(a) printf("%lld\n",(a));
#define pii pair<ll,ll> 
typedef long long ll;
using namespace std;
const int N=5E6+6;
int cen,MR,ans,n;
int p[2*N],f[N];
char a[N],s[2*N];
void print()
{
	rep(i,1,n)
		cout<<s[i]<<" ";
	cout<<endl;
	rep(i,1,n)
		cout<<p[i]<<" ";
	cout<<endl;
}
int main()
{
	scanf("%s",a);
	n=strlen(a);
	s[0]=s[1]='#';
	for(register int i=0;i<n;++i)
	{
		s[(i<<1)+2]=a[i];
		s[(i<<1)+3]='#';
	}
	n<<=1;
	n+=2;
	s[n]='\0';
	for(register int i=1;i<=n;++i)
	{
		p[i]=MR>i?min(p[(cen<<1)-i],MR-i):1;
		while(s[i+p[i]]==s[i-p[i]])
			++p[i];
		if(i+p[i]>MR)
		{
			cen=i;
			MR=i+p[i];
		}
	}
	for(register int i=2;i<=n;i+=2)
	{
		if(p[(i+2)>>1]<(i>>1))
			continue;
		f[i]=f[(i>>2)<<1]+1;
		ans+=f[i];
	}
	cout<<ans<<endl;
}

E

思路

恶心的模拟题。对于一个表达式X=ax+(by+332)X=ax+(by+332)axax后面的加号称为括号外的运算符,首先分类讨论四则运算,对于A+BA+BBB括号外的运算符类型没有任何限制。对于ABA-BBB括号外不能有“++” || “-”(会变号)。对于A*B,AA括号外不能有“++” || “-”且B括号外不能有“++” || “-”(优先级)。对于A÷BA\div BAA括号外不能有“++” || “-”且BB括号外不能有“++” || “-” || “×\times” || “÷\div”。

因为判断是否合法时只有两种情况,一种是括号外有“++” || “-”(称为①),另一种是括号外有“++” || “-” || “×\times” || “÷\div”(称为②)。所以首先预处理出每一个宏定义对应的表达式的括号外运算符的出现情况,把宏定义的表达式分为两类。在判断最终的表达式是否合理时,因为必定先算乘除,所以先把乘除两边的表达式合并成一类,最后判断减法(因为加法总是合理的)。

大体思路如上,接下来说具体实现。

首先是表达式分类,因为每个宏定义的表达式长度不超过100100,可以每出现一个“++” || “-”就给这个宏的映射值+1+1,每出现一个“×\times” || “÷\div”就+1000+1000,设宏的映射值为kk,若k%10000k\%1000\neq 0,则为①,若k>0k>0,则为②。

之后是合法性的判断,宏定义支持递归定义,所以对于每一个新的宏定义都要判断它是否合法,即使他不合法也没关系,只要最终的表达式不调用它就行。所以考虑合法性的继承,也就是如果在宏定义的表达式中所有引用的宏定义都是合法的,且他们拼凑出来的表达式也是合法的,这个宏定义就是合法的。最终的表达式也用同样的流程判定。

另外,程序判定的过程基于对运算符的扫描,如果宏定义的表达式中没有运算符(也就是只有一个元素),就需要判断这个元素在之前的宏定义中是否出现过,如果没出现就当作一个普通元素处理,必然合法;如果出现过且不合法,那么当前的宏定义也是不合法的。

空格到处都有,要特殊处理。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int (i)=(st);(i)<=(ed);++(i))
#define bl(u,i) for(int (i)=head[(u)];(i);(i)=e[(i)].nxt)
#define sf(a) scanf("%lld",&(a));
#define pf(a) printf("%lld\n",(a));
typedef long long ll;
using namespace std;
ll t,n;
map<string,int> p;
map<string,int> has;
map<string,int> valid;
int is(char ch)
{
	if((ch>='A' && ch<='Z') || (ch>='a' && ch<='z'))
		return 1;
	return 0;
}
string qupi(string lon)
{
	string ret="";
	rep(i,0,(int)lon.size()-1)
		if(lon[i]!=' ')
			ret+=lon[i];
	return ret;
}
string getpre(string s,int pos)
{
	string ret="";
	for(int ind=pos;ind>=1 && is(s[ind-1]);--ind)
	{
		if(s[ind-1]!=' ')
			ret+=s[ind-1];
	}
	reverse(ret.begin(),ret.end());
	return ret;
}
string getlst(string s,int pos)
{
	string ret="";
	int n=(int)s.size()-1;
	for(int ind=pos;ind<n && is(s[ind+1]);++ind)
	{
		if(s[ind+1]!=' ')
			ret+=s[ind+1];
	}
	return ret;
}
int judge(string s)
{
	string cur="";
	int val=0;
	int n=s.size()-1;
	rep(i,0,n)
	{
		if(s[i]=='/')
		{
			string fir=getpre(s,i),sec=getlst(s,i);
			if(p[fir]%1000!=0 || p[sec])
				return 0;
			if(cur.size()==0)
			{
				cur+=fir+sec;
				val+=p[fir]+p[sec];
			}
			else
			{
				cur+=sec;
				val+=p[sec];
			}
		}
		else if(s[i]=='*')
		{
			string fir=getpre(s,i),sec=getlst(s,i);
			if(p[fir]%1000 || p[sec]%1000)
				return 0;
			if(cur.size()==0)
			{
				cur+=fir+sec;
				val+=p[fir]+p[sec];
			}
			else
			{
				cur+=sec;
				val+=p[sec];
			}
		}
		else if(s[i]=='+' || s[i]=='-')
		{
			if(cur.size())
			{
				p[cur]=val;
				cur="";
				val=0;
			}
		}
	}
	rep(i,0,n)
	{
		if(s[i]=='-')
		{
			string fir=getpre(s,i),sec=getlst(s,i);
			if(p[sec]%1000)
				return 0;
		}
	}
	rep(i,0,n)
	{
		if(!is(s[i]))
			continue;
		string u=getlst(s,i-1);
		if(has[u] && !valid[u])
			return 0;
		i+=u.size()-1;
	}
	return 1;
}
int main()
{
	string s;
	sf(t)
	int ok=1;
	rep(i,1,t)
	{
		cin>>s;
		if(s[s.size()-1]=='#')
			cin>>s;
		cin>>s;
		string sec;
		getline(cin,sec);
		sec=qupi(sec);
		n=sec.size()-1;
		if(has[sec])
		{
			has[s]=1;
			valid[s]=valid[sec];
			p[s]=p[sec];
			continue;
		}
		valid[s]=judge(sec);
		int add,sub,mul,div;
		add=sub=mul=div=0;
		int cnt=0;
		has[s]=1;
		rep(j,0,n)
		{
			if(!cnt)
			{
				if(sec[j]=='+')
					add+=1;
				else if(sec[j]=='-')
					sub+=1;
				else if(sec[j]=='*')
					mul+=1000;
				else if(sec[j]=='/')
					div+=1000;
			}
			if(sec[j]=='(')
				++cnt;
			else if(sec[j]==')')
				--cnt;
		}
		p[s]=add+sub+mul+div;
	}
	getline(cin,s);
	if(s.size()==0) 
		getline(cin,s);
	s=qupi(s);
	n=s.size()-1;
	if(has[s])
	{
		puts(valid[s]?"OK":"Suspicious");
		return 0;
	}
	if(ok && judge(s))
		puts("OK");
	else
		puts("Suspicious");
}