1. 程式人生 > >清北刷題班day3 morning

清北刷題班day3 morning

div 分類 friends continue dash stdout 處理 字母 兩個

P99
zhx
: 競賽時間:???? 年?? 月?? 日??:??-??:??
題目名稱 a b c
名稱 a b c
輸入 a.in b.in c.in
輸出 a.out b.out c.out
每個測試點時限 1s 1s 1s
內存限制 256MB 256MB 256MB
測試點數目 10 10 10
每個測試點分值 10 10 10
是否有部分分 無 無 無
題目類型 傳統 傳統 傳統
註意 事項) (請務必仔細閱讀) :
P99 zhxa


a
【問題描述】
你是能看到第一題的 friends 呢。
——hja
怎麽快速記單詞呢?也許把單詞分類再記單詞是個不錯的選擇。何大爺給


出了一種分單詞的方法,何大爺認為兩個單詞是同一類的當這兩個單詞的各個
字母的個數是一樣的,如 dog 和 god。現在何大爺給了你?個單詞,問這裏總共
有多少類單詞。
【輸入格式】
第一行一個整數?代表單詞的個數。
接下來?行每行一個單詞。
【輸出格式】
一行一個整數代表答案。
【樣例輸入】
3
AABAC
CBAAA
AAABB
【樣例輸出】
2
【數據範圍與規定】
70%的數據,1 ≤ ? ≤ 100。
對於100%的數據,1 ≤ ? ≤ 10000,所有單詞由大寫字母組成。
P99 zhxb

#include<iostream>
#include<cstdio>
#include
<cstring> #include<set> #include<cstdlib> #include<algorithm> #define N 10007 using namespace std; int len,n; string ch; set<string>s; int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); cin>>n; for(int k=1;k<=n;k++) { cin
>>ch;len=ch.length(); sort(ch.begin(),ch.end()); s.insert(ch); } printf("%d\n",s.size()); fclose(stdin);fclose(stdout); return 0; }


b
【問題描述】
你是能看到第二題的 friends 呢。
——laekov
長度為?的鐵絲,你可以將其分成若幹段,並把每段都折成一個三角形。你
還需要保證三角形的邊長都是正整數並且三角形兩兩相似,問有多少種不同的
分法。
【輸入格式】
一行一個整數?。
【輸出格式】
一行一個整數代表答案對10 9 + 7取模之後的值。
【樣例輸入 1
6
【樣例輸出 1】
2
【樣例輸入 2】
9
【樣例輸出 2】
6
【樣例解釋 2】
(1,1,1),(2,2,2);(2,2,2),(1,1,1)算兩種方案。
【數據範圍與規定】
3。
60%的數據,1 ≤ ? ≤ 1000。
對於100%的數據,1 ≤ ? ≤ 10 6 。
P99 zhxc

/*
首先計算周長為M的三角形有多少個,設為f[M]。設三角形的三邊a,b,c滿足a<=b<=c,那麽分兩種情況:
(1)b=c,此時c的上限為(M-1)/2,下限為ceil(M/3)=(M+2)/3,所以此時的三角形個數為(M-1)/2-(M+2)/3+1;
(2)b!=c,那麽b<=c-1,因為a+b>c>c-1,因此一般來說有多少個三角形(a,b,c-1)就有多少個三角形(a,b,c),但是此時要減去a+b=c的情況。三角形(a,b,c-1)的個數就是f[M-1]。此時若a+b=c,即M-1=a+b+c-1=c+c-1,即M=2c,因此M必須為偶數。a+b=c=M/2,使得a+b=M/2的有序(a<=b)二元組有M/2/2。
根據這兩個可以得到計算f的遞推關系。下面我們看怎麽得到周長為M且三邊滿足Gcd(a,b,c)=1的三角形個數?這個可用於篩素數類似的方法得到。那麽對於n,將其分成若幹份,每份相等,那麽不同的分法就是隔板法。
①相似三角形一定可以找到最小的那個,稱為這類相似三角形的基。
②剩下就是一包夾雜容斥的遞推:
③設w[i]為長度為i的鐵絲的分法,一種分法的所有三角形邊長除以gcd(a,b,c)得到的三角形都一樣,且三邊互質,設邊長為a‘,b‘,c‘。?
④若M=a+b+c,M‘=a‘+b‘+c‘,設k=M/M‘,那麽以a‘,b‘,c‘為三邊的三角形為基,用長度為M的鐵絲能做出的方案數為2^(k-1) (楊輝三角第k層數字和公式)。?
⑤設g[i]為長度為i的鐵絲分成邊長為a,b,c(a<=b<=c)且gcd(a,b,c)=1的三角形的方案數。那麽
  w[i]=g[p1]*2^(i/p1-1)+g[p2]*2^(i/p2-1)+…+g[pk]*2^(i/pk-1)(p為i的因數)。?
⑥設f[i]為長度為i的鐵絲分成邊長為a,b,c(a<=b<=c)的三角形的方案數。那麽
  g[i]=f[i]-f[p1]-f[p2]-…-f[pk](p為i的因數)。(註意此處的f相當於g了,因為是f在刷新自己,因此不會出現因倍數而導致重復情況)
⑦接下來處理三角形三邊合法(即f的遞推):
  1.b==c,c最小為ceil(i/3),最大為floor((i-1)/2) 。?
  2.b<=b<=c-1的方案數,為f[i-1]。?
  第二種情況還要除去a+b=c的方案數。?
  若a+b=c,那麽i=a+b+c=2*(a+b),a+b=i/2,
  這樣的(a,b)有i/2/2對,此時i一定為偶數,所以i為偶數時要考慮這種情況
*/
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=5000005,mod=1000000007;
int n,ans,cnt;
int f[N],p[N];
int main()
{
    p[1]=1;
    for(int i=2; i<=N; i++)p[i]=(p[i-1]*2)%mod;
    f[3]=1;
    for(int i=4; i<=N; i++)
    {
        f[i]=f[i-1]+(i-1)/2-i/3+(i%3?0:1);
        if(i%2==0)f[i]-=i/4;
        f[i]%=mod;
        if(f[i]<0)f[i]+=mod;
    }
    for(int i=2; i<=N; i++)
        for(int j=2; i*j<=N; j++)
        {
            f[i*j]-=f[i];
            if(f[i*j]<0)f[i*j]+=mod;
        }
    while(~scanf("%d",&n))
    {
        ans=0;
        for(int i=1; i*i<=n; i++)
        {
            if(n%i!=0)continue;
            ans=(ans+1ll*f[i]*p[n/i])%mod;
            if(i*i!=n)ans=(ans+1ll*f[n/i]*p[i])%mod;
        }
        printf("%d\n",ans);
    }
    return 0;
}


c
【問題描述】
你是能看到第三題的 friends 呢。
——aoao
在小學的時候,我們都學過正視圖和左視圖。現在何大爺用一些小方塊擺了
一個圖形,並給出了你這個圖形的左視圖和正視圖。現在何大爺希望知道,在給
定正視圖和左視圖的情況下,原來的立體圖形有多少種可能的情況?
【輸入格式】
第一行兩個整數?,?,代表在左視圖和正視圖中分別有多少列。
第二?個整數,代表在左視圖中從左至右每一列的高度。
第三行?個整數,代表在正視圖中從左至有每一列的高度。
【輸出格式】
一行一個整數代表答案對10 9 + 9取模之後的值。
【樣例輸入 1】
2 2
1 1
1 1
【樣例輸出 1】
7
【樣例輸入 2】
4 5
5 2 4 1
5 2 4 0 1
【樣例輸出 2】
429287
【數據規模與約定】
21 ≤ ?,? ≤ 5,每列的最大高度不超過5。
40%的數據,? + ? ≤ 18。
對於100%的數據,1 ≤ ?,? ≤ 50,每列最

/*
排序
容斥原理 
emmmmm
大概就是這麽牛逼
大佬的世界
我們不懂
不懂
不懂
就是不懂
嘿嘿嘿
不懂
絕望
就是不懂
很絕望
看不懂
emmmm 
*/
#include<cstdio>
#include<algorithm>

using namespace std;

typedef long long LL;

#define N 51
#define H 10001
const int mod=1e9+9;

int a[H],b[H];
int n,m;
int C[N][N];

void pre(int k)
{
    for(int i=0; i<=k; i++) C[i][0]=1;
    for(int i=1; i<=k; i++)
        for(int j=1; j<=i; j++)
            C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}

int pow(int a,int b)
{
    int res=1;
    for(; b; b>>=1,a=1ll*a*a%mod)
        if(b&1) res=1ll*res*a%mod;
    return res;
}

int cal(int n,int m,int nn,int mm,int h)
{
    int res=0,tmp;
    for(int i=0; i<=nn; ++i)
        for(int j=0; j<=mm; ++j)
        {
            tmp=1ll*pow(h,n*m-(n-i)*(m-j))*pow(h+1,(n-i)*(m-j)-(n-nn)*(m-mm))%mod*C[nn][i]%mod*C[mm][j]%mod;
            if((i+j)&1) res=((res-tmp)%mod+mod)%mod;
            else res+=tmp,res%=mod;
        }
    return res;
}

int main()
{
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);
    int x;
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; ++i) scanf("%d",&x),a[x]++;
    for(int i=1; i<=m; ++i) scanf("%d",&x),b[x]++;
    pre(max(n,m));
    LL res=1;
    int nown=0,nowm=0;
    for(int i=10000; i>=0; i--)
        if(a[i] || b[i])
        {
            nown+=a[i];
            nowm+=b[i];
            res=1ll*res*cal(nown,nowm,a[i],b[i],i)%mod;
        }
    printf("%I64d",res);
}

清北刷題班day3 morning