“亚信科技杯”南邮第七届大学生程序设计竞赛之网络预赛 (部分题解)
“亚信科技杯”南邮第七届大学生程序设计竞赛之网络预赛
E
Dreaming
总提交 : 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\n", ans); 57 } 58 }
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\n",mi,ma); 51 } 52 53 void dfs(int sum) 54 { 55 //printf(" sum=%d\n",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\n",sum,fenzi,fenmu); 64 if(fenzi%fenmu==0){ 65 y=fenzi/fenmu; 66 //printf(" sum=%d fenzi=%d mu=%d y=%d\n",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\n",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
自动售货机
总提交 : 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\n",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!\n"); 99 } 100 else{ 101 printf("KSS have a dream!\n"); 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 }