2019 Multi-University Training Contest 5

 

补题状况:

题号 1 2 3 4 5 6 7 8 9 10    
状态 Ο Ο . Ο Ο Ο Ο . . .    

1001

题目要求a=b*x mod p,可以转化成a=b*x-p*y    (y为设的变量)

由0

相当于求下面这个式子最小

p/x   <  b/y  <  p/x-1;

等价于找到一个分数   满足分子,分母最小,(分子最小的话,分母肯定对应的也最小)。且在p/x    p/(x-1)之间。

如果不等式左边的上取整t   小于等于  右边的下取整  的话,就说明左边和右边之间有整数,那  y=1,b=t。一定是最小值

如果不存在,我们可以让左边和右边同时减去(t-1),即把左边化成小于1的真分数。然后再左右取倒数。

不等式变成了:(方便书写,我们让t先减1)

(x-1) / ( p- (x-1) * t ) < y / ( b - (t * y) ) < (x)/( p-x*t );

同样的:我们让新的不等式;同样求中间的分数分子分母最小。 

然后我们就可以用递归书写这个过程。

复杂度跟辗转相除一样。好强的方法。。

#include 
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair pii;
typedef pair pll;
typedef pair pdd;
#define F first
#define S second
const ll INF64=8000000000000000000LL;
const int INF=0x3f3f3f3f;
const ld PI=acos(-1);
const ld eps=1e-9;
const ll MOD=ll(1e9+7);
const int M = 1e5 + 10;
void modup(int&x){if(x>=MOD)x-=MOD;}
//unordered_mapmp;
void gao(ll a,ll b,ll c,ll d,ll &x,ll &y)
{
//    printf("%lld")
    ll t=(a+b-1)/b;//向上取整
    if(c/d>=t) 
    {
        y=1,x=t;
        return ;
    }
    else
    {
        t--;
        gao(d,c-d*t,b,a-b*t,y,x);
        x+=t*y;
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ll p,x;
        scanf("%lld%lld",&p,&x);
        ll y,b;
        gao(p,x,p,x-1,b,y);
        ll a=b*x-p*y;
        printf("%lld/%lld\n",a,b);
    }
       return 0;
}


1002

思维+字典树

首先把a,b序列按位建字典树。

有2个对的结论:

1:如果ai与b数组中任意数异或最小的是bj,且bj与a数组中任意数异或最小的是ai。那么ai,bj一定是一组c。

很明显,如果ai,bj不是一对,那么最后我们组成的c一定不是最优的,因为我们只需让ai,bj成一对,那么2对中,这一对变小了,我们把这一对放前面,c的字典序肯定也是整体变小了。

2:ai在b数组中任意数异或最小的是bj,bj在a数组中任意数异或最小的是ak,那么ak在b数组中异或最小的是bl,那么

bl在a数组中异或最小的一定不是ai,只可能是ak或者其他没有在这个关系链上的数。即上述关系只存在2元环,。

证明:ai^bj

 

由上面2个结论我们就可以做这一题了!!!

直接用栈s维护这个有向图找2元环,找到后删除这2个点,在字典树中同样删除,继续询问其他的点。

遍历a数组如果栈空且a数组未被访问(即删除)加入a数组;

然后执行下面循环直到栈为空:

如果s[top]->B,B->s[top], 那么B和s[top]是一对,删除,top--,但注意了:如果此时的s[top]==B,top要再减一。

因为这就相当于栈顶元素找到了栈顶下面一个元素进行配对。

否则继续找。

注意初始化等细节就没问题了

//KX
#include 
using namespace std;
typedef long long ll;
typedef double db;
const int M= 1e5+7;
//结点个数最多30*M 

struct Tri
{
	int ti[M*31][2],val[M*31],cnt[M*31],sz;
	void init()
	{
		sz=0;
		ti[sz][0]=ti[sz][1]=0;
	}
	void in(int x,int d)
	{
		int o=0;
		for(int i=29;i>=0;i--)
		{
			int c=(x>>i)&1;
			if(!ti[o][c])
		 	{
				ti[o][c]=++sz;
				cnt[sz]=ti[sz][0]=ti[sz][1]=0;	
				//初始化 
			}
			o=ti[o][c];
			cnt[o]+=d;//删除操作,沿途经过的结点都减去1 
		}
		val[o]=x;
	}
	int qu(int x)
	{
		int o=0;
		for(int i=29;i>=0;i--)
		{
			int c=(x>>i)&1;
			if(!cnt[ti[o][c]])//当前位指向的相同结点是否存在 
				c^=1;
			o=ti[o][c];
		}
		return val[o];
	}
}tire[2];

int s[M];
int c[M],a[M],b[M];
int main()
{
	int t,n;
	cin>>t;
	while(t--)
	{
		scanf("%d",&n);
		tire[0].init();
		tire[1].init();
		for(int i=1;i<=n;i++)
			scanf("%d",&a[i]),tire[0].in(a[i],1);
		for(int i=1;i<=n;i++)
			scanf("%d",&b[i]),tire[1].in(b[i],1);
		int top=0,cnt=0;
		for(int i=1;i<=n;i++)
		{
			if(cnt

1005

dfs搜索+剪枝判断

因为要找第k小字典序,我们很容易想到用dfs求,因为dfs可以保证按照字典序搜索

我们直接设第一个数为100,然后第二个数从100-n+1到100+n-1之间从小到大取,dfs下去,后面的数一样。

如此保证了差分数组字典序第k小,(我们是从前往后,按从小到大深搜)

每搜到一个解复杂度是n^2   第K小的解 复杂度就是K*n^2

#include
using namespace std;
int vis[110];
int p[110];
bool flag;
int n,k;
void dfs(int tmp,int last,int mi,int mx)
{
//	printf("%d  %d  %d  %d\n",tmp,last,mi,mx);
	if(mx-mi>=n||flag)
	return ;
	//puts("iok");
	if(tmp==n+1)
	{
		k--;
		if(k==0)
		{
			for(int i=1;i<=n;i++)
			printf("%d%c",p[i]-(mi-1)," \n"[i==n]);
			flag=true;
		}
	}
	else
	{
		for(int i=-n+1;i<=n-1;i++)//保证按字典序最小遍历,复杂度最坏也只是K*N^2 
		{
		//	puts("ooooo");
			int nxt=last+i;
			if(!vis[nxt])
			{
				p[tmp]=nxt;
				vis[nxt]=1;
				dfs(tmp+1,nxt,min(mi,nxt),max(mx,nxt));
				vis[nxt]=0;
			}
		}
	}
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		memset(p,0,sizeof(p));
		memset(vis,0,sizeof(vis));
		flag=false;
		scanf("%d%d",&n,&k);
	//	for(int i=100;i>=100-n+1;i--)
		p[1]=100;
		vis[100]=1;
		dfs(2,100,100,100);
	}
	return 0;
}

1007:打表找规律

发现   所有  n  1->n  都满足  a[n]=a[n-1]+a[n-3]这个数组。

然后递推到  任意  i->j    发现结果为a[abs(i-j)+pos],pos为i,j为边界的个数。

1006:扩展KMP裸题。

exnext数组就是题目中的an数组

1004: 大模拟题,就是让n个绝对值消去,有n+1个区间,每个区间对应一个状态,然后直接模拟就行

 

你可能感兴趣的:(多校----牛客/hdu,字符串---字典树)