2014蓝桥国赛C组

标题:排列序数

   如果用a b c d这4个字母组成一个串,有4!=24种,如果把它们排个序,每个串都对应一个序号:

  abcd  0

  abdc  1

  acbd  2

  acdb  3

  adbc  4

  adcb  5

  bacd  6

  badc  7

  bcad  8

  bcda  9

  bdac  10

  bdca  11

  cabd  12

  cadb  13

  cbad  14

  cbda  15

  cdab  16

  cdba  17

  ...

    现在有不多于10个两两不同的小写字母,给出它们组成的串,你能求出该串在所有排列中的序号吗?

【输入格式】

一行,一个串。

【输出格式】

一行,一个整数,表示该串在其字母所有排列生成的串中的序号。注意:最小的序号是0。

例如:

输入:

bdca

程序应该输出:

11

再例如:

输入:

cedab

程序应该输出:

70

#include<bits/stdc++.h>
using namespace std;
char s[12],str[12];
int main()
{
	scanf("%s",s);
	int len=strlen(s);
	for(int i=0;i<len;i++)
		str[i]=s[i];
	sort(str,str+len);
	int cnt=0;
	int flag;
	do{
		flag=1;
		for(int i=0;i<len;i++)
		{
			if(s[i]!=str[i])
			{
				flag=0;
				break;
			}
		}
		if(flag)
		{
			printf("%d\n",cnt);
			break;
		}
		cnt++;
	}while(next_permutation(str,str+len));
	return 0;
}

1e5数据 做法:set + 树状数组

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lowbit(x) x&(-x)
const int N=1e5+10; 
char s[N],str[N],len;
ll f[N];
set<int> st;
int sum[N];
void add(int pos,int val)
{
	while(pos<=len)
	{
		sum[pos]+=val;
		pos+=lowbit(pos);
	}
}
int query(int pos)
{
	int res=0;
	while(pos)
	{
		res+=sum[pos];
		pos-=lowbit(pos);
	}
	return res;
}
int main()
{
	f[0]=1;
	for(int i=1;i<=10;i++)
		f[i]=f[i-1]*i;
	scanf("%s",s);
	len=strlen(s);
	for(int i=0;i<len;i++) str[i]=s[i];
	sort(str,str+len);
	for(int i=0;i<len;i++)
	{
		int pos=lower_bound(str,str+len,s[i])-str;
		s[i]='a'+pos+1;
		st.insert(pos+1);
		add(pos+1,1);
	}
	ll ans=0;
	int cnt;
	for(int i=0;i<len;i++)
	{
		int pos=*st.lower_bound(s[i]-'a');
		cnt=query(pos);
		ans+=(ll)(cnt-1)*f[len-i-1];
		st.erase(pos);
		add(s[i]-'a',-1);
	}
	printf("%lld\n",ans);
	return 0;
}

幂一矩阵:

    atm 不满足幂零矩阵,他自己设想了一个幂一矩阵:对于一个方阵 M ,如果存在一个正整数 k 满足 M^k = I ,其中 I 是单位矩阵,那么 M 就是一个幂一矩阵。

 

    atm 特别钟情于这样一种方阵:每行每列有且仅有一个 1 。经过 atm 不断实验,他发现这种矩阵都是幂一矩阵。

 

    现在,他的问题是,给定一个满足以上条件的方阵,他想求最小的 k 是多少。

 

【输入格式】

第一行一个正整数 n ,表示矩阵大小是 n * n 。

接下来 n 行,每行两个正整数 i j 表示方阵的第 i 行第 j 列为 1。

1 <= i, j <= n 。

行号,列号都从1开始。

 

【输出格式】

一行。一个正整数,即题目中所说最小的 k 。

 

【样例输入】

5

3 1

1 2

4 4

2 3

5 5

 

【样例输出】

3

 

【数据范围】

对于 30% 的数据满足 n <= 10

对于 60% 的数据答案不超过 10^18

对于 100% 的数据满足 n <= 10000

 

求所有到达(i,i)位置次数的最小公倍数

60%:

#include<bits/stdc++.h>
using namespace std;
int v1[10010];
int n;
int main()
{
    scanf("%d",&n);
    int x,y;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&x,&y);
        v1[x]=y;
    }
    long long ans=1;
    long long cnt;
    for(int i=1;i<=n;i++)
    {
        cnt=1;
        x=v1[i];
        while(x!=i)
        {
            cnt++;
            x=v1[x];    
        } 
    //  cout<<cnt<<endl;
        ans=ans*cnt/__gcd(ans,cnt);
    }
    cout<<ans<<endl;
    return 0;
}

100%  大数:

#include<bits/stdc++.h>
using namespace std; 
 
#define MAXN 9999
#define MAXSIZE 10
#define DLEN 4
 
class BigNum
{ 
private: 
	int a[500];    //可以控制大数的位数 
	int len;       //大数长度
public: 
	BigNum(){ len = 1;memset(a,0,sizeof(a)); }   //构造函数
	BigNum(const int);       //将一个int类型的变量转化为大数
	BigNum(const char*);     //将一个字符串类型的变量转化为大数
	BigNum(const BigNum &);  //拷贝构造函数
	BigNum &operator=(const BigNum &);   //重载赋值运算符,大数之间进行赋值运算
 
	friend istream& operator>>(istream&,  BigNum&);   //重载输入运算符
	friend ostream& operator<<(ostream&,  BigNum&);   //重载输出运算符
 
	BigNum operator+(const BigNum &) const;   //重载加法运算符,两个大数之间的相加运算 
	BigNum operator-(const BigNum &) const;   //重载减法运算符,两个大数之间的相减运算 
	BigNum operator*(const BigNum &) const;   //重载乘法运算符,两个大数之间的相乘运算 
	BigNum operator/(const int   &) const;    //重载除法运算符,大数对一个整数进行相除运算
 
	BigNum operator^(const int  &) const;    //大数的n次方运算
	int    operator%(const int  &) const;    //大数对一个int类型的变量进行取模运算    
	bool   operator>(const BigNum & T)const;   //大数和另一个大数的大小比较
	bool   operator>(const int & t)const;      //大数和一个int类型的变量的大小比较
	bool   operator==(const BigNum & T)const;  // 大数和大数判断相等
	bool   operator==(const int & t)const;     // 大数和int类型判断相等 
 
	void print();       //输出大数
}; 
BigNum::BigNum(const int b)     //将一个int类型的变量转化为大数
{ 
	int c,d = b;
	len = 0;
	memset(a,0,sizeof(a));
	while(d > MAXN)
	{
		c = d - (d / (MAXN + 1)) * (MAXN + 1); 
		d = d / (MAXN + 1);
		a[len++] = c;
	}
	a[len++] = d;
}
BigNum::BigNum(const char*s)     //将一个字符串类型的变量转化为大数
{
	int t,k,index,l,i;
	memset(a,0,sizeof(a));
	l=strlen(s);   
	len=l/DLEN;
	if(l%DLEN)
		len++;
	index=0;
	for(i=l-1;i>=0;i-=DLEN)
	{
		t=0;
		k=i-DLEN+1;
		if(k<0)
			k=0;
		for(int j=k;j<=i;j++)
			t=t*10+s[j]-'0';
		a[index++]=t;
	}
}
BigNum::BigNum(const BigNum & T) : len(T.len)  //拷贝构造函数
{ 
	int i; 
	memset(a,0,sizeof(a)); 
	for(i = 0 ; i < len ; i++)
		a[i] = T.a[i]; 
} 
BigNum & BigNum::operator=(const BigNum & n)   //重载赋值运算符,大数之间进行赋值运算
{
	int i;
	len = n.len;
	memset(a,0,sizeof(a)); 
	for(i = 0 ; i < len ; i++) 
		a[i] = n.a[i]; 
	return *this; 
}
istream& operator>>(istream & in,  BigNum & b)   //重载输入运算符
{
	char ch[MAXSIZE*4];
	int i = -1;
	in>>ch;
	int l=strlen(ch);
	int count=0,sum=0;
	for(i=l-1;i>=0;)
	{
		sum = 0;
		int t=1;
		for(int j=0;j<4&&i>=0;j++,i--,t*=10)
		{
			sum+=(ch[i]-'0')*t;
		}
		b.a[count]=sum;
		count++;
	}
	b.len =count++;
	return in;
 
}
ostream& operator<<(ostream& out,  BigNum& b)   //重载输出运算符
{
	int i;  
	cout << b.a[b.len - 1]; 
	for(i = b.len - 2 ; i >= 0 ; i--)
	{ 
		cout.width(DLEN); 
		cout.fill('0'); 
		cout << b.a[i]; 
	} 
	return out;
}
 
BigNum BigNum::operator+(const BigNum & T) const   //两个大数之间的相加运算
{
	BigNum t(*this);
	int i,big;      //位数   
	big = T.len > len ? T.len : len; 
	for(i = 0 ; i < big ; i++) 
	{ 
		t.a[i] +=T.a[i]; 
		if(t.a[i] > MAXN) 
		{ 
			t.a[i + 1]++; 
			t.a[i] -=MAXN+1; 
		} 
	} 
	if(t.a[big] != 0)
		t.len = big + 1; 
	else
		t.len = big;   
	return t;
}
BigNum BigNum::operator-(const BigNum & T) const   //两个大数之间的相减运算 
{  
	int i,j,big;
	bool flag;
	BigNum t1,t2;
	if(*this>T)
	{
		t1=*this;
		t2=T;
		flag=0;
	}
	else
	{
		t1=T;
		t2=*this;
		flag=1;
	}
	big=t1.len;
	for(i = 0 ; i < big ; i++)
	{
		if(t1.a[i] < t2.a[i])
		{ 
			j = i + 1; 
			while(t1.a[j] == 0)
				j++; 
			t1.a[j--]--; 
			while(j > i)
				t1.a[j--] += MAXN;
			t1.a[i] += MAXN + 1 - t2.a[i]; 
		} 
		else
			t1.a[i] -= t2.a[i];
	}
	t1.len = big;
	while(t1.a[t1.len - 1] == 0 && t1.len > 1)
	{
		t1.len--; 
		big--;
	}
	if(flag)
		t1.a[big-1]=0-t1.a[big-1];
	return t1; 
} 
 
BigNum BigNum::operator*(const BigNum & T) const   //两个大数之间的相乘运算 
{ 
	BigNum ret; 
	int i,j,up; 
	int temp,temp1;   
	for(i = 0 ; i < len ; i++)
	{ 
		up = 0; 
		for(j = 0 ; j < T.len ; j++)
		{ 
			temp = a[i] * T.a[j] + ret.a[i + j] + up; 
			if(temp > MAXN)
			{ 
				temp1 = temp - temp / (MAXN + 1) * (MAXN + 1); 
				up = temp / (MAXN + 1); 
				ret.a[i + j] = temp1; 
			} 
			else
			{ 
				up = 0; 
				ret.a[i + j] = temp; 
			} 
		} 
		if(up != 0) 
			ret.a[i + j] = up; 
	} 
	ret.len = i + j; 
	while(ret.a[ret.len - 1] == 0 && ret.len > 1)
		ret.len--; 
	return ret; 
} 
BigNum BigNum::operator/(const int & b) const   //大数对一个整数进行相除运算
{ 
	BigNum ret; 
	int i,down = 0;   
	for(i = len - 1 ; i >= 0 ; i--)
	{ 
		ret.a[i] = (a[i] + down * (MAXN + 1)) / b; 
		down = a[i] + down * (MAXN + 1) - ret.a[i] * b; 
	} 
	ret.len = len; 
	while(ret.a[ret.len - 1] == 0 && ret.len > 1)
		ret.len--; 
	return ret; 
}
int BigNum::operator %(const int & b) const    //大数对一个int类型的变量进行取模运算    
{
	int i,d=0;
	for (i = len-1; i>=0; i--)
	{
		d = ((d * (MAXN+1))% b + a[i])% b;  
	}
	return d;
}
BigNum BigNum::operator^(const int & n) const    //大数的n次方运算
{
	BigNum t,ret(1);
	int i;
	if(n<0)
		exit(-1);
	if(n==0)
		return 1;
	if(n==1)
		return *this;
	int m=n;
	while(m>1)
	{
		t=*this;
		for( i=1;i<<1<=m;i<<=1)
		{
			t=t*t;
		}
		m-=i;
		ret=ret*t;
		if(m==1)
			ret=ret*(*this);
	}
	return ret;
}
bool BigNum::operator>(const BigNum & T) const   //大数和另一个大数的大小比较
{ 
	int ln; 
	if(len > T.len)
		return true; 
	else if(len == T.len)
	{ 
		ln = len - 1; 
		while(a[ln] == T.a[ln] && ln >= 0)
			ln--; 
		if(ln >= 0 && a[ln] > T.a[ln])
			return true; 
		else
			return false; 
	} 
	else
		return false; 
}
bool BigNum::operator >(const int & t) const    //大数和一个int类型的变量的大小比较
{
	BigNum b(t);
	return *this>b;
}
bool BigNum::operator==(const BigNum & T) const  //大数和大数判断相等 
{
	if(len != T.len) return false;
	for(int i = 0; i < len; i++)
	{
		if(a[i] != T.a[i])	return false;
	}
	return true;
} 
bool BigNum::operator==(const int & t) const  // 大数和int类型的变量判断相等 
{
	BigNum b(t);
	return *this==b;
}
void BigNum::print()    //输出大数
{ 
	int i;   
	cout << a[len - 1]; 
	for(i = len - 2 ; i >= 0 ; i--)
	{ 
		cout.width(DLEN); 
		cout.fill('0'); 
		cout << a[i]; 
	} 
	cout << endl;
}

int v1[10010];
int n;
int main()
{
//	cout<<1<<endl;
    scanf("%d",&n);
    int x,y;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&x,&y);
        v1[x]=y;
    }
    BigNum ans=1;
    int cnt=1;
    for(int i=1;i<=n;i++)
    {
        cnt=1;
        x=v1[i];
        while(x!=i)
        {
            cnt=cnt+1;
            x=v1[x];    
        }
    	if(ans%cnt != 0)
    	{
    		ans=ans*BigNum(cnt)/__gcd(cnt,ans%cnt);
    	//	cout<<cnt<<endl;
		}
        
    }
    ans.print();
    return 0;
}

标题:重复模式

 

    作为 drd 的好朋友,技术男 atm 在 drd 生日时送给他一个超长字符串 S 。atm 要 drd 在其中找出一个最长的字符串 T ,使得 T 在 S 中至少出现了两次,而他想说的秘密就藏在 T 中。

 

    由于字符串实在是太长了,drd 总是找不到合适的 T 。于是 drd 请你帮他找到这个 T 的长度。

 

【输入格式】

一行。一个字符串,即题目中说的S 。

 

【输出格式】

一行。一个整数,表示最长的 T 的长度。

 

【样例输入】

ababa

 

【样例输出】

3

 

「数据范围」

对于 30% 的数据,S长度 <= 100

对于 60% 的数据,S长度 <= 8000

对于 100% 的数据,S长度 <= 500000

n^4:

#include<bits/stdc++.h>
using namespace std;
string s;
int main()
{
	cin>>s;
	int ans=0;
	int len=s.size();
	for(int i=0;i<len;i++)
	{
		for(int j=1;j<len;j++)
		{
			if(s.find(s.substr(i,j),i+1)!=-1)
				ans=max(ans,j);
			else
				break;
		}
	}
	cout<<ans<<endl;
	return 0;
}

n^3:

//  400
#include<bits/stdc++.h>
using namespace std;
string s;
int nex[1010];
int len;
void getnex(int l,int r)
{
	int i=l,j=-1;
	nex[i]=-1;
	while(i<=r)
	{
		if(j==-1 || s[i]==s[j])
		{
			if(j==-1)
			{
				i++,j=l;
				nex[i]=j;
			}
			else nex[++i]=++j;
		}
		else j=nex[j];
	}
}
int solve(int l,int r,int pos)
{
	int i=l,j=pos;
	while(j<len)
	{
		if(i==-1 || s[i]==s[j])
		{
			if(i==-1) i=l,j++;
			else i++,j++;
		}
		else i=nex[i];
		if(i==r+1) return 1;
	}
	return 0;
}
int main()
{
	cin>>s;
	int ans=0;
	len=s.size();
	for(int i=0;i<len;i++)
	{
		for(int j=i;j<len;j++)
		{
			getnex(i,j);
			if(solve(i,j,i+1)) ans=max(ans,j-i+1);
			else break;
		}
	}
	cout<<ans<<endl;
	return 0;
}

n^2log(n):

// 1000
#include<bits/stdc++.h>
using namespace std;
string s[50010];
string str;
int main()
{
	cin>>str;
	int len=str.size();
	string cnt="";
	for(int i=len-1;i>=0;i--)
	{
		cnt=(char)str[i]+cnt;
		s[i]=cnt;
	}
	sort(s,s+len);
	int ans=0;
	int l;
	for(int i=1;i<len;i++)
	{
		l=min(s[i].size(),s[i-1].size());
		for(int j=0;j<l;j++)
		{
			if(s[i][j]!=s[i-1][j]) break;
			ans=max(j+1,ans);
		}
	}
	cout<<ans<<endl;
	return 0;
}

n^2:

// 10000
#include<bits/stdc++.h>
using namespace std;
int len;
string s;
int main()
{
	cin>>s;
	len=s.size();
	int ans=0;
	int cnt;
	for(int i=1;i<len;i++)
	{
		cnt=0;
		for(int j=i,k=0;j<len;j++,k++)
		{
			if(s[j]==s[k])
			{
				cnt++;
				ans=max(ans,cnt);
			}
			else
			cnt=0;
		}
	}
	cout<<ans<<endl;
	return 0;
}

nlog(n):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
typedef long long ll;
const int N=510000;
int t1[N],t2[N],sum[N],rk[N],ht[N],sa[N],str[N],n;
char s[N];
void get_sa(int n,int m)
{
	int *x=t1,*y=t2;
	for(int i=0;i<m;i++) sum[i]=0;
	for(int i=0;i<n;i++) sum[x[i]=str[i]]++;
	for(int i=1;i<m;i++) sum[i]+=sum[i-1];
	for(int i=n-1;i>=0;i--) sa[--sum[x[i]]]=i;
	for(int p,j=1;p<=n;j<<=1)
	{
		p=0;
		for(int i=n-j;i<n;i++) y[p++]=i;
		for(int i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
		for(int i=0;i<m;i++) sum[i]=0;
		for(int i=0;i<n;i++) sum[x[y[i]]]++;
		for(int i=1;i<m;i++) sum[i]+=sum[i-1];
		for(int i=n-1;i>=0;i--) sa[--sum[x[y[i]]]]=y[i];
		swap(x,y);
		p=1;
		x[sa[0]]=0;
		for(int i=1;i<n;i++) x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;
		if(p>=n) break;
		m=p;
	}
	int k=0;n--;
	for(int i=0;i<=n;i++) rk[sa[i]]=i;
	for(int i=0;i<n;i++)
	{
		if(k)k--;else k=0;
		int j=sa[rk[i]-1];
		while(str[i+k]==str[j+k])k++;
		ht[rk[i]]=k; 
	}
}
int main()
{
	int T;
	char s[500100];
	scanf("%s",s);
	n=strlen(s);
	for(int i=0;i<n;i++) str[i]=s[i];
	str[n]=0;
	get_sa(n+1,256);
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		ans=max(ans,ht[i]);	
	} 
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/mmk27_word/article/details/89260853