Codeforces Round #359 (Div. 2) C. Robbers' watch

题目链接:传送门

题目大意:有一只表,由7进制表示,你将一天分为n个小时,将一小时分为m分钟,要求表上显示的数字各不相同,问在n,m的限制下有多少种合法的时间表示

     例如 n=2,m=3 (0: 1), (0: 2), (1: 0), (1: 2).  n=8,m=2 (02: 1), (03: 1), (04: 1), (05: 1), (06: 1).

题目思路:因为是由7进制表示,所以手表上显示的数字不能超过7个,否则必然有重复的(不合法),因此我们只需要特判一下,然后dfs即可。

     这个题还是比较可惜的,当时晚上没做出来,早上起来发现边界情况有点问题,改了一下就过了,自己还是太弱。。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <cctype>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <climits>
#define lson root<<1,l,mid
#define rson root<<1|1,mid+1,r
#define fi first
#define se second
#define ping(x,y) ((x-y)*(x-y))
#define mst(x,y) memset(x,y,sizeof(x))
#define mcp(x,y) memcpy(x,y,sizeof(y))
using namespace std;
#define gamma 0.5772156649015328606065120
#define MOD 1000000007
#define inf 0x3f3f3f3f
#define N 100005
#define maxn 1005
typedef pair<int,int> PII;
typedef long long LL;

int n,m,k,x,num,y;
int vis[10],ans;
void dfs2(int sum,int cnt){ ///dfs2处理分钟段(m),其他和dfs1同理
    if(sum>=m)return;
    if(cnt==y){++ans;return;}
    for(int i=0;i<7;++i){
        if(!vis[i]){
            vis[i]=1;
            sum=sum*7+i;
            dfs2(sum,cnt+1);
            sum=(sum-i)/7;
            vis[i]=0;
        }
    }
}
void dfs1(int sum,int cnt){///dfs1处理小时段(n),sum表示当前时间(sum<n),
    if(sum>=n)return ;     ///cnt表示已经处理了几位数字
    if(cnt==x){
        for(int j=0;j<7;++j)if(!vis[j]){
            vis[j]=1;
            dfs2(j,1);
            vis[j]=0;
        }
    }
    for(int i=0;i<7;++i){
        if(!vis[i]){
            vis[i]=1;
            sum=sum*7+i;
            dfs1(sum,cnt+1);
            sum=(sum-i)/7;
            vis[i]=0;
        }
    }
}
int deal(int x){    ///特殊处理,返回表示n,m需要多少位数字
    int cnt=0;
    while(x){
        ++cnt;
        x=x/7;
    }
    return cnt;
}
int main(){
    int i,j,group,v;
    scanf("%d%d",&n,&m);
    if(n%7==0)x=deal(n-1);///这里需要注意,如果n能被7整除
    else x=deal(n);       ///那么表示n所需要的数字位数要减一,也就是这没考虑清楚,很可惜。
    if(m%7==0)y=deal(m-1);///m同理处理
    else y=deal(m);
    if(x+y>7){exit(0*printf("0\n"));}
    for(i=0;i<7;++i){
        vis[i]=1;
        dfs1(i,1);
        vis[i]=0;
    }
    printf("%d\n",ans);
    return 0;
}

 看了下官方题解,发现其实有更简便的思想

用一个used数组,记录0~6这7个数字使用情况,然后小时从0枚举到n-1,分钟从0枚举到m-1,如果used数组使用情况合法ans++

不过好像比上面的搜索要慢一些(搜索15ms,枚举46ms)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <cctype>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <climits>
#define lson root<<1,l,mid
#define rson root<<1|1,mid+1,r
#define fi first
#define se second
#define ping(x,y) ((x-y)*(x-y))
#define mst(x,y) memset(x,y,sizeof(x))
#define mcp(x,y) memcpy(x,y,sizeof(y))
using namespace std;
#define gamma 0.5772156649015328606065120
#define MOD 1000000007
#define inf 0x3f3f3f3f
#define N 100005
#define maxn 1005
typedef pair<int,int> PII;
typedef long long LL;

int n,m,k,x,num,y;
int vis[10],ans;

int deal(int x){    ///特殊处理,返回表示n,m需要多少位数字
    int cnt=0;
    while(x){
        ++cnt;
        x=x/7;
    }
    return cnt;
}
int used[10];
int main(){
    int i,j,group,v;
    scanf("%d%d",&n,&m);
    if(n%7==0)x=deal(n-1);
    else x=deal(n);
    if(m%7==0)y=deal(m-1);
    else y=deal(m);
    if(x+y>7){exit(0*printf("0\n"));}
    for(i=0;i<n;++i){
        for(j=0;j<m;++j){
            mst(used,0);
            int t1=i,cnt=0;
            while(cnt++<x){
                ++used[t1%7];
                t1/=7;
            }
            t1=j;cnt=0;
            while(cnt++<y){
                ++used[t1%7];
                t1/=7;
            }
            if(*max_element(used,used+7)<=1)++ans;
        }
    }
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2016-06-24 08:30  Kurokey  阅读(160)  评论(0编辑  收藏  举报