2012 Multi-University Training Contest 10
官方解题报告:http://page.renren.com/601081183/note/867254911
1001 Number Sequence 容斥定理+组合数
hdu http://acm.hdu.edu.cn/showproblem.php?pid=4390
题意:
给你b1,b2,...bn个数,求存在多少个这样的序列a1,a2,a3....an满足a1*a2*a3*a3...an = b1*b2...*bn; ai>1
思路:
首先多谢日华兄热心的给我讲解,现在算是明白点了吧。a1*a2...*an = sum;我们首先将sum的所有质因子分解出来,然后就是将质因子分配到N个ai里面求有多少种可能。
sum = p1^k1*p2^k2*p3^k3*....*pn^kn
首先我们不考虑ai>1.那么我们的结果就是c(n + k1 - 1,k1 - 1)*c(n + k2 - 1,k2 -1)......*c(n + k3 - 1,k3 - 1); (c(n + ki - 1,ki -1)排列里面的挡板法) 只用组合数就可求得,二这里ai>1 也就是说每个ai必须分配到一个素因子,所以我们这里用容斥定理来求,枚举n到0表示a1 - an要分配素因子的位数,当有n位时时我们要求的解,可是这里用上述办法求的话就包含了ai = 1的情况情况,所以我们要去掉多加的。就用容斥定理;
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <set> #include <map> #include <string> #define CL(a,num) memset((a),(num),sizeof(a)) #define iabs(x) ((x) > 0 ? (x) : -(x)) #define Min(a,b) (a) > (b)? (b):(a) #define Max(a,b) (a) > (b)? (a):(b) #define ll __int64 #define inf 0x7f7f7f7f #define MOD 1000000007ll #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define test puts("<------------------->") #define maxn 1000007 #define N 1000005 #define M 200007 using namespace std; int prime[N],idx; int cnt[N],num[N],m; int n; bool hash[maxn]; ll c[90][90]; void init() { int i,j; CL(c,0); for (i = 0; i < 90; ++i)//求组合数 c[i][i] = c[i][0] = 1; for (i = 1; i < 90; ++i) { for (j = 1; j < i; ++j) { c[i][j] = (c[i - 1][j] + c[i - 1][j - 1])%MOD; } } //筛选素数 CL(hash,false); idx = 0; for (i = 2; i*i < maxn; ++i) { if (!hash[i]) { for (j = i + i; j < maxn; j += i) { hash[j] = true; } } } for (i = 2; i < maxn; ++i) { if (!hash[i]) prime[idx++] = i; } } void gao(int a)//枚举出sum的质因子即质因子个数 { int i; for (i = 0; i < idx && a != 1; ++i) { while (a % prime[i] == 0) { cnt[i]++; a /= prime[i]; } } } ll cal(int cc) { ll sum = c[n][cc];//首先从n个位置去cc个分配素因子 for (int i = 0; i < m; ++i) { sum *= c[cc + num[i] - 1][cc - 1];//将每个素因子分配 if (sum >= MOD) sum %= MOD; } return sum; } int main() { //freopen("din.txt","r",stdin); int i,a; init(); while (~scanf("%d",&n)) { CL(cnt,0); for (i = 0; i < n; ++i) { scanf("%d",&a); gao(a); } m = 0; for (i = 0; i < idx; ++i) { if (cnt[i]) num[m++] = cnt[i]; } ll ans = 0; int flag = 1; for (i = n; i >= 0; --i) { //ans += flag*cal(i); if(flag == -1) ans -= cal(i);//容斥处理 else ans += cal(i); ans = (ans%MOD + MOD)%MOD; flag *= -1; } printf("%I64d\n",ans); } return 0; }
1004 hdu 4393 Throw nails
http://acm.hdu.edu.cn/showproblem.php?pid=4393
题意:
n名队员参加自行车比赛,在第一秒内每个人都可以行走fi的距离,随后每个人都以各自的速度vi匀速往前前进,在每一秒LZ会扔出一个钉子,是走在最前边的选手爆胎淘汰,问输出选手们被淘汰的顺序,ps:如果行走的距离相同即两人在都以为置时,优先选择标号小的爆胎。
思路:
比赛时,只想到了O(N^2)的解法,这样肯定会超时,想了很长时间还是没有想到哎思路啊.这里关键在于速度速度最大才能达到100我们只需要开一个优先队列数组q[1..100]每次在这些优先队列里面取出f最大的,因为属于同样队列的速度肯定相同所以F大的肯定排在前边,然后就是取最值的问题了,时间复杂度为O(N*100).这里真的很巧妙就是没想出来。。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <set> #include <map> #include <string> #define CL(a,num) memset((a),(num),sizeof(a)) #define iabs(x) ((x) > 0 ? (x) : -(x)) #define Min(a,b) (a) > (b)? (b):(a) #define Max(a,b) (a) > (b)? (a):(b) #define ll long long #define inf 0x7f7f7f7f #define MOD 100000007 #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define test puts("<------------------->") #define maxn 50004 #define N 107 #define M 200007 using namespace std; struct node { int f,v; int pos; friend bool operator < (const node &a,const node &b) { if (a.f != b.f) return a.f < b.f; else return a.pos > b.pos; } }tp; priority_queue<node>q[N]; int main() { //freopen("din.txt","r",stdin); int t,cas = 1; int n,i,j; scanf("%d",&t); while (t--) { printf("Case #%d:\n",cas++); scanf("%d",&n); for (i = 1; i <= 100; ++i) { while (!q[i].empty()) q[i].pop(); } for (i = 1; i <= n; ++i) { scanf("%d%d",&tp.f,&tp.v); tp.pos = i; q[tp.v].push(tp); } int tmp1,tmp2; int MIN; for (i = 0; i < n; ++i) { MIN = -inf; for (j = 1; j <= 100; ++j) { if (!q[j].empty()) { tp = q[j].top(); if (MIN < i*j + tp.f) { MIN = i*j + tp.f; tmp1 = j; tmp2 = tp.pos; } else if (MIN == i*j + tp.f && tmp2 > tp.pos)//注意这里距离相同时,取pos最小的 { tmp1 = j; tmp2 = tp.pos; } } } q[tmp1].pop(); if (i != n - 1) printf("%d ",tmp2); else printf("%d\n",tmp2); } } return 0; }
1005 hdu 4394 http://acm.hdu.edu.cn/showproblem.php?pid=4394
题意:
M2%10x=N (x=0,1,2,3....) 给你N求最小的非负整数M。。。
思路:
这里N到了10^9次方,计算几个式子可以发现,对于b为数的平方,他的平方后的数的后b为也就由它确定了,我们由N去枚举找M,最高只要枚举到第九位也就可以了。
23*23 = 329 123*123 = 15129 3123*3123 = 9753129 观察他们就会发现。
#define MOD 100000007 #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) using namespace std; ll len[] = {1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000,10000000000ll}; int ans; int getlen(int x) { int i; for (i = 0; ; ++i) if (len[i] > x) return i; } void dfs(int x,int l,int xx,int maxL) { int i; if (l == maxL) { if (ans > x) ans = x; return ; } for (i = 0; i < 10; ++i) { ll tmp = len[l]*i + x; if ((tmp*tmp)%len[l + 1] == xx%len[l + 1])//满足继续枚举 dfs(tmp,l + 1,xx,maxL); } } int main() { int t,n; scanf("%d",&t); while (t--) { ans = inf; scanf("%d",&n); int maxL = getlen(n); dfs(0,0,n,maxL); if (ans == inf) printf("None\n"); else printf("%d\n",ans); } }
1007 hdu 4396 More lumber is required
http://acm.hdu.edu.cn/showproblem.php?pid=4396
思路:二维SPFA:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <set> #include <map> #include <string> #define CL(a,num) memset((a),(num),sizeof(a)) #define iabs(x) ((x) > 0 ? (x) : -(x)) #define Min(a,b) (a) > (b)? (b):(a) #define Max(a,b) (a) > (b)? (a):(b) #define maxn 50004 #define N 5007 #define M 200007 #define K 507 #define ll long long #define inf 0x7f7f7f7f #define MOD 100000007 #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) using namespace std; int dis[N][55]; struct node { int v; int w; int next; }g[M]; struct mode { int pos; int k; }tp; int head[N],ct; int n,m,S,T,ki; bool vt[N][55]; void init() { ct = 0; CL(head,-1); CL(vt,false); } void add(int u,int v,int w) { g[ct].v = v; g[ct].w = w; g[ct].next = head[u]; head[u] = ct++; } void spfa() { int i,j; for (i = 0; i <= n; ++i) { for (j = 0; j <= ki; ++j) { dis[i][j] = inf; } } dis[S][0] = 0; tp.k = 0; tp.pos = S; queue<mode>q; q.push(tp); vt[S][0] = true; while (!q.empty()) { mode cur = q.front(); q.pop(); int u = cur.pos; vt[u][cur.k] = false; for (i = head[u]; i != -1; i = g[i].next) { int v = g[i].v; int k = cur.k; int w = g[i].w; int tmp = k + 1; if (tmp > ki) tmp = ki; if(dis[v][tmp] > dis[u][k] + w) { dis[v][tmp] = dis[u][k] + w; if (!vt[v][tmp]) { vt[v][tmp] = true; tp.k = tmp; tp.pos = v; q.push(tp); } } } } } int main() { //freopen("din.txt","r",stdin); int i,u,v,w; while (~scanf("%d%d",&n,&m)) { init(); for (i = 0; i < m; ++i) { scanf("%d%d%d",&u,&v,&w); add(u,v,w); add(v,u,w); } scanf("%d%d%d",&S,&T,&ki); if (ki%10 == 0) ki /= 10; else ki = ki/10 + 1; spfa(); if (dis[T][ki] == inf) puts("-1"); else printf("%d\n",dis[T][ki]); } return 0; }