清北刷题班day3 morning

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);
}

 

posted @ 2017-10-13 15:35  安月冷  阅读(321)  评论(0编辑  收藏  举报