• “亚信科技杯”南邮第七届大学生程序设计竞赛之网络预赛 (部分题解)


    “亚信科技杯”南邮第七届大学生程序设计竞赛之网络预赛

     

     E

    Dreaming

    时间限制(普通/Java) : 1000 MS/ 3000 MS          运行内存限制 : 65536 KByte
    总提交 : 84            测试通过 : 4 

    题目描述

    我们定义一个数good当且仅当它只由a和b构成,且数位和sum各数位也仅由a和b构成。举个栗子:若a=1,b=2,那么13不是good,11是(都由a=1构成,数位和sum=2由b=2构成)。那么窝们定义一个数的长度为n,那么有多少个数是good呢?所求答案对10^9+7取模。


    输入

     

    多组样例。

    每行包含三个数a,b,n(1<=a,b<=9,1<=n<=10^6)

    输出

     

    每组数据输出一个整数。

    样例输入

    1 3 3

    样例输出

    1

     

    题目来源

    NUPT

    题解:

    1.这题就是要求,使用i个a,n-i个b,如果满足条件,ans+=C(n,i);

    2.这题n比较大,故直接枚举这个数比较耗时,可以改为枚举数位和sum,sum最大为 9*1e6,故复杂度大大下降。

    3.n比较大,故C[n][i]用数组存不下,直接递推也会超时,可以考虑用最基本的公式 C(n,k)=(n!)/(k!)/(n-k)!  ,然后除法采用逆元操作。

      可以使用公式 (a/b)%mod=a*b^(mod-2)%mod  ,如果b与mod互质的话。 不过,小明哥给了一个更好的递推公式,见代码。

    关于逆元详解:

    http://blog.csdn.net/acdreamers/article/details/8220787

     1 ll f[N];        //n!
     2 ll inv[N];      //逆元
     3 ll nf[N];       //n!的逆元
     4 int mi,ma;
     5 ll ans;
     6 
     7 void pre()
     8 {
     9     inv[0] = inv[1] = 1;
    10     f[0] = f[1] = 1;
    11     nf[0] = nf[1] = 1;
    12     for (int i = 2; i < N; i++) {
    13         inv[i] = ((mod - mod / i) * inv[mod % i]) % mod;
    14         f[i] = (f[i - 1] * i)%mod;
    15         nf[i] = (nf[i - 1] * inv[i])%mod;
    16     }
    17 }

    思路来源于小明哥,先转一发小明哥的代码:

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<iostream>
     4 #include<cmath>
     5 using namespace std;
     6 int a[100005];
     7 __int64 pmod = 1000000009;
     8 __int64 inv[100005];
     9 __int64 ba[100005];
    10 __int64 rba[100005];
    11 #define M 100005
    12 void pre() {
    13     inv[0] = inv[1] = 1;
    14     ba[0] = ba[1] = 1;
    15     rba[0] = rba[1] = 1;
    16     for (int i = 2; i < M; i++) {
    17         inv[i] = ((pmod - pmod / i) * inv[pmod % i]) % pmod;
    18         ba[i] = (ba[i - 1] * i)%pmod;
    19         rba[i] = (rba[i - 1] * inv[i])%pmod;
    20     }
    21 }
    22 __int64 C(int n, int k) {
    23     return (ba[n] * rba[k] % pmod )* rba[n - k] % pmod;
    24 }
    25 int main() {
    26     int n, m;
    27     int l, r;
    28     int i;
    29     int nl, nr;
    30     pre();
    31     while (scanf("%d%d", &n, &m) != EOF) {
    32         for (i = 0; i < n; ++i) {
    33             scanf("%d", &a[i]);
    34         }
    35         l = 0;
    36         r = 1;
    37         int o = 0;
    38         for (i = 0; i < n; ++i) {
    39             nl = min(abs(l - a[i]), abs(r - a[i]));
    40             if (l <= a[i] && r >= a[i])
    41                 nl = 0;
    42             nr = max(m - abs(l + a[i] - m), m - abs(r + a[i] - m));
    43             if (l <= m - a[i] && r >= m - a[i])
    44                 nr = m;
    45             o = (o + a[i]) % 2;
    46             l = nl;
    47             r = nr;
    48         }
    49         __int64 ans = 0;
    50         for (i = l; i <= r; ++i) {
    51             if (i % 2 == o) {
    52                 ans += C(m, i);
    53                 ans %= pmod;
    54             }
    55         }
    56         printf("%I64d
    ", ans);
    57     }
    58 }
    View Code
    Accepted
    375MS
      23688K
    1991Byte
    2015-03-31 15:26:51.0
      1 #include <cstdio>
      2 #include <cstring>
      3 #include <stack>
      4 #include <vector>
      5 #include <algorithm>
      6 #include <map>
      7 #include <string>
      8 #include <queue>
      9 
     10 #define ll long long
     11 int const N = 1000005;
     12 int const M = 100005;
     13 int const inf = 1000000000;
     14 ll const mod = 1000000007;
     15 
     16 using namespace std;
     17 
     18 int n,a,b;
     19 ll f[N];        //n!
     20 ll inv[N];      //逆元
     21 ll nf[N];       //n!的逆元
     22 int mi,ma;
     23 ll ans;
     24 
     25 void pre()
     26 {
     27     inv[0] = inv[1] = 1;
     28     f[0] = f[1] = 1;
     29     nf[0] = nf[1] = 1;
     30     for (int i = 2; i < N; i++) {
     31         inv[i] = ((mod - mod / i) * inv[mod % i]) % mod;
     32         f[i] = (f[i - 1] * i)%mod;
     33         nf[i] = (nf[i - 1] * inv[i])%mod;
     34     }
     35 }
     36 
     37 ll calC(int n, int k)
     38 {
     39     return (f[n] * nf[k] % mod )* nf[n - k] % mod;
     40 }
     41 
     42 void ini()
     43 {
     44     if(b<a){
     45         swap(a,b);
     46     }
     47     mi=a*n;
     48     ma=b*n;
     49     ans=0;
     50    // printf("  mi=%d ma=%d
    ",mi,ma);
     51 }
     52 
     53 void dfs(int sum)
     54 {
     55     //printf(" sum=%d
    ",sum);
     56     if(sum>ma){
     57         return;
     58     }
     59     if(sum>=mi){
     60         int fenzi=sum-mi;
     61         int fenmu=b-a;
     62         int y;
     63         //printf("  sum=%d fenzi=%d mu=%d
    ",sum,fenzi,fenmu);
     64         if(fenzi%fenmu==0){
     65             y=fenzi/fenmu;
     66             //printf("  sum=%d fenzi=%d mu=%d y=%d
    ",sum,fenzi,fenmu,y);
     67             if(y>=0 && y<=n){
     68                 ans=(ans+calC(n,y))%mod;
     69             }
     70         }
     71     }
     72     dfs(sum*10+a);
     73     dfs(sum*10+b);
     74 }
     75 
     76 void solve()
     77 {
     78     if(a==b){
     79         int ssum=n*a;
     80         while(ssum){
     81             int yu=ssum%10;
     82             if(yu!=a){
     83                 return;
     84             }
     85             ssum/=10;
     86         }
     87         ans++;
     88         return;
     89     }
     90     dfs(0);
     91 }
     92 
     93 void out()
     94 {
     95     printf("%I64d
    ",ans);
     96 }
     97 
     98 int main()
     99 {
    100     pre();
    101     //freopen("data.in","r",stdin);
    102     //freopen("data.out","w",stdout);
    103     //scanf("%d",&T);
    104     //for(int cnt=1;cnt<=T;cnt++)
    105     //while(T--)
    106     while(scanf("%d%d%d",&a,&b,&n)!=EOF)
    107     {
    108         ini();
    109         solve();
    110         out();
    111     }
    112 }

    F

    自动售货机

    时间限制(普通/Java) : 1000 MS/ 3000 MS          运行内存限制 : 65536 KByte
    总提交 : 60            测试通过 : 13 

    题目描述

    教学楼有一台奇怪的自动售货机,它只售卖一种饮料,单价5元,并且只收5元、10元面值的货币,但是同学们都很喜欢喝。这个售货机里没有多余的找零,也就是说如果一个持有10元的同学第一个购买,则他不能获得5元找零,但是如果在他之前有一个持有5元的同学买了这种饮料,则他可以获得5元找零。

    假设售货机的货源无限,每人只买一罐,现在有N个持有5元的同学和M个持有10元的同学想要购买,问一共有多少种排队方法可以让每个持有10元的同学都获得找零。(这里的排队方法以某一位置上人持的钱数来分,即只要同一位置上的同学所持钱的数目相同,就算同一种排队方法)


    输入

     

    多组测试数据

    每组包含两个整数N,M(1<=M<=N<=1000),分别表示持有5元和10元的同学个数。

    输出

     

    输出一个整数,表示排队方法总数。由于结果可能很大,所以结果需要模1000000007。

    样例输入

    1 1
    2 1
    3 1

    样例输出

    1
    2
    3

     

    题目来源

    hjp

    题解转自田神:

    http://blog.csdn.net/tc_to_top/article/details/44745987

    题目分析:这题其实很简单,开始想的太复杂了,开始当作卡特兰数 (Catalan数)做其实就是(C(n+m, m)%mod - C(n+m, m-1)%mod)%mod,数组递推组合数T了 ,用java写大数结果noj上mle,连乘组合数取余写跪了,下面说这题应该怎么做。

    其实就是一个dp,dp[i][j]表示有i个人有5元,j个人有10元的排队方案数,我们可以发现:

    dp[i][0] = 1,因为大家都只有5元,怎么排都是一种方案

    i < j时dp[i][j] = 0,因为有5元的人比有10元的少,必然会出现找不开的情况,那么此时方案数就是0

    不是以上两种情况时:dp[i][j]的方案数由dp[i - 1][j] + dp[i][j - 1]递推得到,考虑第m+n个人的状态

    1.第m+n个人100,m+n-1里有m个50,n-1个100则dp[m][n-1]
    2.第m+n个人50,m+n-1里有m-1个50,n个100则dp[m-1][n]

     

     

    最后竟然忘了先预处理算一遍,- -

     

    Accepted
    937MS
      16020K
    887Byte
    2015-03-30 20:03:08.0
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <stack>
     4 #include <vector>
     5 #include <queue>
     6 #include <algorithm>
     7 
     8 #define ll long long
     9 int const N = 1005;
    10 int const M = 205;
    11 int const inf = 1000000000;
    12 ll const mod = 1000000007;
    13 
    14 using namespace std;
    15 
    16 ll dp[2*N][N];
    17 int n,m;
    18 
    19 void ini1()
    20 {
    21     memset(dp,0,sizeof(dp));
    22     dp[1][0]=1;
    23     int i,j;
    24     for(i=2;i<=2000;i++){
    25         for(j=0;j<=i/2;j++){
    26             dp[i][j]=(dp[i-1][j-1]+dp[i-1][j])%mod;
    27         }
    28     }
    29 }
    30 
    31 void ini()
    32 {
    33 
    34 }
    35 
    36 void solve()
    37 {
    38 
    39 }
    40 
    41 void out()
    42 {
    43     printf("%I64d
    ",dp[n+m][m]);
    44 }
    45 
    46 int main()
    47 {
    48     ini1();
    49     //freopen("data.in","r",stdin);
    50    // freopen("data.out","w",stdout);
    51     //scanf("%d",&T);
    52     //for(int cnt=1;cnt<=T;cnt++)
    53    // while(T--)
    54     while(scanf("%d%d",&n,&m)!=EOF)
    55     {
    56         ini();
    57         solve();
    58         out();
    59     }
    60 }

    H:

     KSS的金牌梦1
    时间限制(普通/Java) : 3000 MS/ 9000 MS          运行内存限制 : 65536 KByte
    总提交 : 56            测试通过 : 7

    题目描述
    KSS是nupt集训队里公认的最具有金牌实力的选手,熟练掌握多种金牌算法,但是由于队友水平太菜和自身情绪不稳定,一直没能拿到金牌。KSS为了圆梦,想为自己制定一个训练计划,那么问题来了:
    ACM中有许多算法之间是有单方面依赖关系的,比如:想学会A,就必须先学B,由于KSS很聪明,所以它可以学完A再学B;当然也存在两种或多种算法相互交融的情况,比如:想学会A,就必须先学B,想学会B,就必须先学A,这种情况KSS就不知从何下手了。
    现在给出KSS打算学习的一些算法之间的依赖关系,KSS将尽自己最大的努力去学习这些算法。再给出比赛会出现的算法,如果KSS能学会超过70%的比赛算法,他就能圆梦,否则,他只能含恨退役。

    输入
    多组测试用例。
    第一行一个整数N(0<=N<=250000)表示有N对算法间存在依赖关系,保证涉及的算法总数不超过500
    接下来N行每行有两个字符串(以空格分割),表示前一个算法依赖后一个算法,第N+1行有一个整数M(0<M<=1000)表示比赛会出现M个算法,接下来M行每行有一个字符串表示比赛出现的算法。(字符串保证不含空格)

    输出
    如果KSS可以圆梦,输出“Excelsior!”,否则,输出“KSS have a dream!”。(不用输出引号)

    样例输入
    4
    Aho-Corasickautomaton KMP
    Aho-Corasickautomaton trietree
    Inclusion-ExclusionPrinciple Mobiusinversion
    Mobiusinversion Inclusion-ExclusionPrinciple
    5
    KMP
    trietree
    Aho-Corasickautomaton
    Splay
    Suffixarray

    样例输出
    KSS have a dream!

    提示
    对于样例,KSS可以学会KMP、trietree、Aho-Corasickautomaton,但是并不能学会Inclusion-ExclusionPrinciple、Mobiusinversion,所以只能掌握60%的比赛算法

    题目来源
    hjp

    题目分析转自田神:

    http://blog.csdn.net/tc_to_top/article/details/44745987
    题目分析:最伤心的一题。。。其实并不难可是全场就2人过还是在最后时候,所以并没有开它而是选择一直被数论坑着,赛后一下就补出来了。

    这题就是裸的拓扑排序,出题人比较良心,没有卡map和cin的时间,不然字符串hash写就麻烦了,所以直接map存一下,建个图,拓扑排个序最后判断一下就行了,吐槽一下,我还是相信kss可以拿到金牌的

    简单说下拓扑排序,就是用栈维护一个入读为0的点集,每次删点(出栈)然后修改图上各剩余点的入度,再将入度为0的点入栈,一直到栈为空,即不存在入度为0的点为止

    Accepted
    1812MS
      1496K
    2136Byte
    2015-03-31 14:44:13.0
      1 #include <cstdio>
      2 #include <cstring>
      3 #include <stack>
      4 #include <vector>
      5 #include <algorithm>
      6 #include <map>
      7 #include <string>
      8 #include <queue>
      9 
     10 #define ll long long
     11 int const N = 505;
     12 int const M = 100005;
     13 int const inf = 1000000000;
     14 ll const mod = 1000000007;
     15 
     16 using namespace std;
     17 
     18 int n;
     19 map<string,int>mp;
     20 vector<int> bian[N];
     21 int r[N];
     22 int ok[N];
     23 int tot;
     24 int sum;
     25 int m;
     26 char s1[M],s2[M];
     27 int vis[N];
     28 
     29 void ini()
     30 {
     31     mp.clear();
     32     memset(r,0,sizeof(r));
     33     memset(ok,0,sizeof(ok));
     34     memset(vis,0,sizeof(vis));
     35     tot=0;
     36     sum=0;
     37     int i;
     38     for(i=0;i<=500;i++){
     39         bian[i].clear();
     40     }
     41     for(i=1;i<=n;i++){
     42         scanf("%s%s",s1,s2);
     43         if(mp.count(s1)==0){
     44             tot++;mp[s1]=tot;
     45         }
     46         if(mp.count(s2)==0){
     47             tot++;mp[s2]=tot;
     48         }
     49         int te1,te2;
     50         te1=mp[s1];
     51         te2=mp[s2];
     52         r[te1]++;
     53         bian[te2].push_back(te1);
     54     }
     55 }
     56 
     57 void solve()
     58 {
     59     queue<int>que;
     60     int i;
     61     int te;
     62     vector<int>::iterator it;
     63     for(i=1;i<=tot;i++){
     64         if(r[i]==0){
     65             que.push(i);
     66             vis[i]=1;
     67         }
     68     }
     69     while(que.size()>=1){
     70         te=que.front();
     71         que.pop();
     72         ok[te]=1;
     73         for(it=bian[te].begin();it!=bian[te].end();it++){
     74             int y=*it;
     75             r[y]--;
     76             if(r[y]==0 && vis[y]==0){
     77                 que.push(y);
     78                 vis[y]=-1;
     79             }
     80         }
     81     }
     82 
     83     scanf("%d",&m);
     84     for(i=1;i<=m;i++){
     85         scanf("%s",s1);
     86         if(mp.count(s1)!=0){
     87             te=mp[s1];
     88             if(ok[te]==1){
     89                 sum++;
     90             }
     91         }
     92     }
     93 }
     94 
     95 void out()
     96 {
     97     if(sum*10>=m*7){
     98         printf("Excelsior!
    ");
     99     }
    100     else{
    101         printf("KSS have a dream!
    ");
    102     }
    103 }
    104 
    105 int main()
    106 {
    107     //freopen("data.in","r",stdin);
    108     //freopen("data.out","w",stdout);
    109     //scanf("%d",&T);
    110     //for(int cnt=1;cnt<=T;cnt++)
    111     //while(T--)
    112     while(scanf("%d",&n)!=EOF)
    113     {
    114         ini();
    115         solve();
    116         out();
    117     }
    118 }
  • 相关阅读:
    6_10 下落的树叶(UVa699)<二叉树的DFS>
    6_9 天平(UVa839)<二叉树的DFS>
    6_8 树(UVa548)<从中序和后序恢复二叉树>
    6_7 树的层次遍历(UVa122)<二叉树的动态创建与BFS>
    6_6 小球下落(UVa679)<完全二叉树编号>
    6_4 破损的键盘(UVa11988)<链表>
    6_3 矩阵链乘(UVa424)<用栈实现简单的表达式解析>
    6_2 铁轨(UVa514)<栈>
    第五周课程总结&试验报告(三)
    第四周课程总结和实验报告
  • 原文地址:https://www.cnblogs.com/njczy2010/p/4379034.html
Copyright © 2020-2023  润新知