Xuzhou Winter Camp 2補題

A ID Codes
求一串字符串字典序的下一個排列。

#include<string>
#include<iostream>
#define INF 2147483647
#define N 60
using namespace std;
string code;
int main(){
	while(cin>>code && code!="#")
	{
		if(next_permutation(code.begin(),code.end()))
            cout<<code<<endl;
        else
            cout<<"No Successor"<<endl;

	}
	return 0;
}  

B Generating Fast
求給定字符串的字典序全排列(STL還真是什麼都能做啊

#include<cstdio>
#include<string>
#include<iostream>
#include<algorithm>
#define INF 2147483647
#define N 60
using namespace std;
string s;
int main(){
	int n;
	scanf("%d",&n);
	while(n--)
	{
		cin>>s;
		sort(s.begin(),s.end());
		cout << s << endl;
		while (next_permutation(s.begin(),s.end()))
            cout<<s<<endl;
        cout<<endl;
	}
	return 0;
}  

C Binomial Showdown
求組合數,時間複雜度爲O(T*k)。

#include<cstdio>
#include<iostream>
#include<algorithm>
#define LL long long 
using namespace std;
LL C(int n,int k){
    LL ans = 1;
    k = min(k,n-k);//單個計算爲O(k)複雜度
    if (k)
    {
        for (LL i = 1;i <= k; i++)
        {
        	ans *= n-i+1;
        	ans /= i;
        }
    }
    return ans;
} 
int main(){
    int n,k;
    while(scanf("%d%d",&n,&k) && n)
    {
        cout << C(n,k)<<endl;
    }
    return 0;
}

F Game of Connections

Catalan數 + 大數處理
(網上copy的模板

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <stdlib.h>
#include <string.h>
#include <iomanip>
#define N 110
#define INF 10000000
#define LL long long
#define eps 10E-9
#define MAXN 9999
#define MAXSIZE 10
#define DLEN 4
using namespace std;
class BigNum
{
private:
    int a[MAXN];    //能夠控制大數的位數
    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類型的變量的大小比較    
};
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[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;
}
int main(){
    BigNum x[N];     
    x[0]=1;
    for(int i = 1; i < N; i++)
        x[i] = x[i-1] * (4*i-2) / (i+1);
    int n;
    while(scanf("%d",&n) && n!=-1)
    { 
        cout << x[n]<<endl;
    }
    return 0;
}

**H Rhyme Schemes **
題意:把n個元素放入m個等價類的方法數目(每個類都不能爲空)。
解法:第二類Stirling數

  • (1)如果n個元素構成了m-1個集合,那麼第n+1個元素單獨構成一個集合。
    方案數 S(n, m-1)。
  • (2)如果n個元素已經構成了m個集合,將第n+1個元素插入到任意一個集合。方案數 m*S(n, m)。
  • 綜合兩種情況得:

    注:集合數不能少於元素數。
//主程序部分
int main(){
    BigNum dp[N][N];
    for (int i = 1; i < N; i++)
        dp[i][1] = 1;
    for (int i = 2; i < N; i++)
        for (int j = 2; j <= i; j++)
    {
        dp[i][j] = dp[i-1][j]*j + dp[i-1][j-1];
    }        
    int n;
    while(cin >> n && n)
    {   
        BigNum ans = 0;
        for (int i = 1; i <= n; i++) 
            ans = ans + dp[n][i];
        cout << n<<' '<<ans<<endl;
    }
    return 0;
}

I X-factor Chains
題意:將一個數X分解成從1到X的數列,前一個數可以整除後一個數,求最大鏈長和鏈的個數。
分析:因爲題目裏要求Xi | Xi+1,而Xm又限定爲X,所以我們可以想到Xm-1是X除以其某個約數得到的,Xm-1也是可以由Xm-2的到的,可以認爲這些單位之間就是插入了一個乘數。
由此我們可以知道“X-factor Chains”是通過不斷乘以X的約數得到的,爲了長度最大,所以約數必須是素數。
最終,題目轉化成求一個數的素因子的排列數:總的因子數的階乘除以重複的因子數的階乘。

#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>
#define INF 2147483647
#define LL long long 
#define N 110
using namespace std;
int n;
vector<int> p;
LL fact(int x){
    LL ans=1;
    for(int i = 1; i <= x; i++)
        ans *= i;        
    return ans;
}

int main(){
    while(~scanf("%d",&n))
    {
        p.clear();
        int x = n;
        for(int i = 2; i*i <= x; i++)
    	{
    		int t = 0;
    		while(x % i == 0) 
    		{
    			t++;
    			x/=i;
    		}
        	p.push_back(t);
    	}
    	if(x!=1) p.push_back(1);

        int sump = 0;
       	for(int i = 0; i < p.size(); i++)
           	sump+=p[i];

       	LL ans = fact(sump);
       	for(int i = 0; i < p.size(); i++)
           	ans/=fact(p[i]);       

       	printf("%d %lld\n",sump,ans);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章