A题 (hdu 4505)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4505
解题思路: 一次遍历就可以,这道题可以推出公式 max*10+(k*5)+n
max最高楼层,k多少个楼层需要开门,n一共多少个人
代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 400 int a[MAX]; int main() { int t,n,i,j,m,k,max; scanf("%d",&t); while(t--) { scanf("%d",&n); memset(a,0,sizeof(a)); for(i=0,k=0,max=0;i<n;i++) { scanf("%d",&m); if(a[m]==0) k++; a[m]++; if(m>max) max=m; } printf("%d\n",max*10+(k*5)+n); } return 0; }
B题 (hdu 4506)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4506
解题思路: 一个个求多少次方速度很慢,可以用快速幂
代码:
#include<stdio.h> __int64 a[10005]; __int64 get_mi(__int64 a,__int64 b,int n) { if(0 == a) return 0; if(0 == b) return 1; __int64 r=1; while(b) { if(b&1) r=(r*a)%n; a=(a*a)%n; b>>=1; } return r; } int main() { int T,i,y; __int64 n,t,k; scanf("%d",&T); while(T--) { scanf("%I64d%I64d%I64d",&n,&t,&k); for(i=0;i<n;i++) { scanf("%I64d",&a[i]); } __int64 x; int mmm=1000000007; __int64 sum; sum=get_mi(k,t,mmm); t%=n; for(i=0;i<n-1;i++) { if(i<t) y=i+n-t; else y=i-t; x=(a[y]*sum)%mmm; printf("%I64d ",x); } if(i<t) y=i+n-t; else y=i-t; x=(a[y]*sum)%mmm; printf("%I64d\n",x); } return 0; }
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4508
解题思路: 经典DP,完全背包的模版题,不一定要把背包装满
代码:
#include <stdio.h> #include <string.h> #define MAX_N 100001 #define MAX_V 100001 #define _MAX -0x3f3f3f3f int n,m,f[MAX_V],c[MAX_N],w[MAX_N]; int DP(int full) { int i,v; if(full) //如果是恰好放满,则除f[0][0]外都初始化为无穷小 { memset(f,_MAX,sizeof(f)); f[0]=0; } else memset(f,0,sizeof(f)); //如果不一定要放满,则初始化为0 for(i=1;i<=n;i++) { for(v=c[i];v<=m;v++) { f[v]=(f[v-c[i]]+w[i]>f[v])?f[v-c[i]]+w[i]:f[v]; // ****状态转移方程**** } } return f[m]; } int main () { int i; while(scanf("%d",&n)!=EOF) { for(i=1;i<=n;i++) { scanf("%d%d",&w[i],&c[i]); } scanf("%d",&m); printf("%d\n",DP(0)); //0为非满,1非恰好满 } return 0; }
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4509
解题思路: 开始没有考虑到时间会有交叉的情况,WA了两次
把分钟转换成数字,那么24小时就有24*60=1440
构建数组a[1440],初始化为-1
每行给出的两个时间都可以转换成一个区间存不存在
如 01:00 02:00,转换成a[60]到a[120]所有的元素都为0
这道题可以用线段树优化,但是数组不大,效果不那么明显
可以用memset代替for,效率高一点
代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 2000 int time[MAX]; int main() { int n,i,t,a,b,c,d,s,k; while(scanf("%d",&n)!=EOF) { memset(time,-1,sizeof(time)); //-1代表空闲 for(i=0;i<n;i++) { scanf("%d:%d %d:%d",&a,&b,&c,&d); s=a*60+b; t=c*60+d; memset(time+s,0,(t-s)*sizeof(time[0])); //memset代替for循环 } //0代表忙碌 for(i=0,k=0;i<1440;i++) if(time[i]==-1) k++; printf("%d\n",k); } return 0; }
C题(hdu 4507)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4507
解题思路: 位DP的思想,转载一下大牛的思路
典型的按位dp。一开始想会不会是数学结论题,但是很快觉得数学一点不靠谱,然后发现按位dp可做。
求出区间[0, N]中满足条件的数的平方和,这样可以不用卡下界。
定义数组dp[ d ][ u ][ i ][ j ],d表示dp到第d位,u表示是否卡上界(按惯例,0表示卡上界),i表示前缀的各位数字和模7为i,j表示前缀表示的整数模7为j。每个元素存num、sum、ssum三个值。num表示满足条件的前缀数量,sum则是这些前缀表示的整数的和,ssum是这些前缀表示的整数的平方和。
dp从最高位到最低位枚举p,再枚举当前位的数字d,并枚举上一位p+1位的dp数组最后两维i:0~6,j:0~6。计算出转移到p位时的余数值:
ii = (i + d)%7 jj = (j * 10 + d)%7
最基本的转移方程是:
dp[ p ][ 1 ][ ii ][ jj ].num += dp[ p + 1][ 1 ][ i ][ j ];
dp[ p ][ 1 ][ ii ][ jj ].sum += dp[ p + 1 ][ 1 ][ i ][ j ].sum * 10
+ dp[ p + 1 ][ 1 ][ i ][ j ].num * d;
dp[ p ][ 1 ][ ii ][ jj ].ssum += dp[ p + 1 ][ 1 ][ i ][ j ].ssum * 100
+ dp[ p + 1 ][ 1 ][ i ][ j ].sum * 20 * d
+ d * d * dp[ p + 1 ][ 1 ][ i ][ j ].num;
//zzy.2013.3.21AC #include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define ll long long #define MOD (1000000007LL) typedef struct { ll num,sum,ssum; }node; ll digits[21]; node dp[21][2][7][7]; void ini(ll len) { for(ll i = 1; i <= len + 1; ++i){ for(ll j = 0; j < 2; ++j){ for(ll k = 0; k < 7; ++k){ for(ll m = 0; m < 7; ++m){ dp[i][j][k][m].num = 0; dp[i][j][k][m].sum = 0; dp[i][j][k][m].ssum = 0; } } } } } ll Len(ll N) { ll ret = 0; while(N){ ret ++; digits[ret] = N % 10; N = N / 10; } return ret; } void DP(ll len) { for(ll p = len; p > 0; p--) { for(ll d = 0; d <= 9; d++) { if(d == 7) continue; for(ll i=0; i<7; i++) { for(ll j=0; j<7; j++) { ll ii,jj; ii = (i+d)%7; jj = (j*10+d)%7; dp[p][1][ii][jj].sum += dp[p+1][1][i][j].sum*10 + dp[p+1][1][i][j].num*d; if(d < digits[p]) dp[p][1][ii][jj].sum += dp[p+1][0][i][j].sum*10 + dp[p+1][0][i][j].num*d; dp[p][1][ii][jj].sum %= MOD; dp[p][1][ii][jj].num += dp[p+1][1][i][j].num; if(d < digits[p]) dp[p][1][ii][jj].num += dp[p+1][0][i][j].num; dp[p][1][ii][jj].num %= MOD; dp[p][1][ii][jj].ssum += dp[p+1][1][i][j].ssum * 100LL + 20LL * d * dp[p+1][1][i][j].sum + d*d * dp[p+1][1][i][j].num; if(d < digits[p]) dp[p][1][ii][jj].ssum += dp[p+1][0][i][j].ssum * 100LL + 20LL * d * dp[p+1][0][i][j].sum + d*d * dp[p+1][0][i][j].num; dp[p][1][ii][jj].ssum %= MOD; } } } ll d = digits[p]; if(d == 7) continue; for(ll i=0; i<7; i++) { for(ll j=0; j<7; j++)if(dp[p+1][0][i][j].num) { ll ii,jj; ii = (i+d)%7; jj = (j*10+d)%7; dp[p][0][ii][jj].sum += dp[p+1][0][i][j].sum*10 + dp[p+1][0][i][j].num*d; dp[p][0][ii][jj].sum %= MOD; dp[p][0][ii][jj].num += dp[p+1][0][i][j].num; dp[p][0][ii][jj].num %= MOD; dp[p][0][ii][jj].ssum += dp[p+1][0][i][j].ssum * 100LL + 20LL * d * dp[p+1][0][i][j].sum + d*d * dp[p+1][0][i][j].num; dp[p][0][ii][jj].ssum %= MOD; } } } } ll calcu(ll N) { ll len = Len(N); ini(len); dp[len+1][0][0][0].num = 1; DP(len); ll ret = 0; for(ll i=1; i<7; i++){ for(ll j=1; j<7; j++){ ret += dp[1][0][i][j].ssum; ret += dp[1][1][i][j].ssum; } } ret %= MOD; return ret; } int main() { ll T; cin >> T; while(T--){ ll A,B; cin >> A >> B; ll ans = 0; ans = calcu(B) - calcu(A - 1); ans = (ans + MOD) % MOD; cout << ans << endl; } return 0; }注:原创文章,转载请注明出处: http://blog.csdn.net/qq7366020