题意
数字时钟每秒钟会消耗显示的数字所需的能量,给定时间长度m和起点st,求m秒内会消耗的能量
思路
没有什么比看错题目却一直没发现更悲催的了。。。
队友和我说了题意,然后我想都没想就开始写了,一直以为前导零是不需要计算代价的,虽然样例就是有前导零的。。
就这样带着错误的思路打了三个小时。。
好吧,不怪队友,谁让自己连样例都不看呢。。
这题的打法很多,延续昨天想到的思路,用数位dp来做
我们用dp[i][j]表示长度为i,以j开头,形式为jxxxx所需的代价总和。
因为后面的x的范围一定是0000-FFFF,所以代价可以直接推算出来
如果是0000-FFFF,那么一共有16^4个数字,0-F各出现(16^3)*4次,其实和数位dp已经没太大关系了,毕竟是可以直接推出答案而不需要递推的
代码(前导零不计代价,错误思路)
思路错了以后代码实现更复杂一些,但是也是能用数位dp做出来的
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i=a;i<b;i++)
#define sc(a) scanf("%d",&a)
const int INF=0x3f3f3f3f;
const int maxn=2e5+50;
const int mod=1e9+7;
const double eps=1e-8;
#define pii pair<int,int>
typedef long long ll;
typedef unsigned int ui;
using namespace std;
ll val[16]={6,2,5,5,4,5,6,3,7,6,6,5,4,5,5,4};
inline ll pow16(ll i){
return (1ll<<(i*4));
}
inline char toChar(int x){
assert(x>=0 && x<16);
if(x>=0 && x<=9) return x+'0';
return x+'A'-10;
}
inline int toInt(char x){
if(x>='0' && x<='9') return x-'0';
return x-'A'+10;
}
ll bruteForce(int x){
ll ret=0;
while(x>=0){
char buf[66]={0};
sprintf(buf,"%08X",x);
if(x==0) ret+=val[0];
int len=strlen(buf);
int pos=0;
while(buf[pos]=='0') pos++;
for(;pos<8;pos++) ret+=val[toInt(buf[pos])];
x--;
}
return ret;
}
string toHex(ll x){
string ret="";
for(int i=0;i<8;i++){
ret=toChar(x%16)+ret;
x=x/16;
}
return ret;
}
ll toLL(char buf[]){
ll ret=0;
int len=strlen(buf);
rep(i,0,len) ret=ret*16+toInt(buf[i]);
return ret;
}
//dp i j len-i start-j tot-val
ll dp[9][17];
//dp[i][0] no-leading-zeros
//dp[i][16] start with 0 and have leading-zeros
void init(){
mem(dp,0);
rep(i,0,16) dp[1][i]=val[i];
dp[1][16]=val[0];
rep(i,2,9){
rep(j,0,16) dp[i][0]+=dp[i-1][j];
ll num=pow16(i-1);
rep(j,1,16){
dp[i][j]=val[j]*num+num/16*(i-1)*78;
}
dp[i][16]=val[0]*num+num/16*(i-1)*78;
}
rep(i,1,5) rep(j,0,17) printf("%d %d %lld\n",i,j,dp[i][j]);
}
ll st,ed;
ll LIM=0xFFFFFFFF;
void debugHex(int x){
printf("%08X\n",x);
}
ll cal(ll x){
if(x<0) return 0;
if(x==0) return 6;
string buf=toHex(x);
bool flag=true;
int pos=0;
while(buf[pos]=='0') pos++;
int num;
ll base=0;
ll ret=0;
for(;pos<8;pos++){
int i=8-pos;
num=toInt(buf[pos]);
if(num){
if(flag){
ret+=dp[i][0];
}else ret+=dp[i][16]+base*pow16(i-1);
flag=false;
}
rep(j,1,num){
ret+=dp[i][j]+base*pow16(i-1);
}
if(pos==7) ret+=dp[i][num]+base*pow16(i-1);
base+=val[num];
printf("i:%d pos:%d num:%d base:%lld ret:%lld\n",i,pos,num,base,ret);
}
return ret;
}
int main()
{
#ifndef ONLINE_JUDGE
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
#endif
init();
char buf[233];
while(~scanf("%s",buf)){
st=toLL(buf);
cout<<"= ="<<cal(st)<<" normal "<<bruteForce(st)<<endl;
}
int T; sc(T);
while(T--){
int n;
scanf("%d %s",&n,buf);
st=toLL(buf);
ed=(st+n-1)%LIM;
debugHex(st);
debugHex(ed);
ll ans;
if(st<=ed){
ans=cal(ed)-cal(st-1);
}else{
ans=cal(LIM)-cal(st-1)+cal(ed-1);
}
printf("%lld\n",ans);
}
return 0;
}
代码(按照题意)
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i=a;i<b;i++)
#define sc(a) scanf("%d",&a)
const int INF=0x3f3f3f3f;
const int maxn=2e5+50;
const int mod=1e9+7;
const double eps=1e-8;
#define pii pair<int,int>
typedef long long ll;
typedef unsigned int ui;
using namespace std;
ll val[16]={6,2,5,5,4,5,6,3,7,6,6,5,4,5,5,4};
inline ll pow16(ll i){
return (1ll<<(i*4));
}
inline char toChar(int x){
assert(x>=0 && x<16);
if(x>=0 && x<=9) return x+'0';
return x+'A'-10;
}
inline int toInt(char x){
if(x>='0' && x<='9') return x-'0';
return x-'A'+10;
}
ll bruteForce(int x){
ll ret=0;
while(x>=0){
char buf[66]={0};
sprintf(buf,"%08X",x);
rep(pos,0,8) ret+=val[toInt(buf[pos])];
x--;
}
return ret;
}
string toHex(ll x){
string ret="";
for(int i=0;i<8;i++){
ret=toChar(x%16)+ret;
x=x/16;
}
return ret;
}
ll toLL(char buf[]){
ll ret=0;
int len=strlen(buf);
rep(i,0,len) ret=ret*16+toInt(buf[i]);
return ret;
}
//dp i j len-i start-j tot-val
ll dp[9][16];
//dp[i][0] start with 0 and have leading-zeros
void init(){
mem(dp,0);
rep(i,0,16) dp[1][i]=val[i];
dp[1][16]=val[0];
rep(i,2,9){
ll num=pow16(i-1);
rep(j,0,16) dp[i][j]=val[j]*num+num/16*(i-1)*78;
}
//rep(i,1,5) rep(j,0,16) printf("%d %d %lld\n",i,j,dp[i][j]);
}
ll st,ed;
ll LIM=0xFFFFFFFF;
void debugHex(int x){
printf("%08X\n",x);
}
ll cal(ll x){
if(x<0) return 0;
if(x==0) return 6;
string buf=toHex(x);
int pos=0,num;
ll base=0,ret=0;
while(buf[pos]=='0') {
pos++;
base+=val[0];
}
for(;pos<8;pos++){
int i=8-pos;
num=toInt(buf[pos]);
ll sz=pow16(i-1);
rep(j,0,num){
ret+=dp[i][j]+base*sz;
}
if(pos==7) ret+=dp[i][num]+base*sz;
base+=val[num];
//printf("i:%d pos:%d num:%d base:%lld ret:%lld\n",i,pos,num,base,ret);
}
return ret;
}
int main()
{
#ifndef ONLINE_JUDGE
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
#endif
init();
char buf[233];
// while(~scanf("%s",buf)){
// st=toLL(buf);
// cout<<"= ="<<cal(st)<<" normal "<<bruteForce(st)<<endl;
// }
int T; sc(T);
while(T--){
int n;
scanf("%d %s",&n,buf);
st=toLL(buf);
ed=(st+n-1)%LIM;
// debugHex(st);
// debugHex(ed);
ll ans;
if(st<=ed){
ans=cal(ed)-cal(st-1);
}else{
ans=cal(LIM)-cal(st-1)+cal(ed-1);
}
printf("%lld\n",ans);
}
return 0;
}
本文介绍了一种使用数位动态规划方法解决数字时钟能耗计算问题的思路与实现过程,包括考虑前导零的情况和按照实际题意的两种解决方案。
2331

被折叠的 条评论
为什么被折叠?



