BestCoder Round #75

题目链接:戳这里

King's Cake  

Accepts: 960   Submissions: 1572
 Time Limit: 2000/1000 MS (Java/Others)   Memory Limit: 65536/65536 K (Java/Others)
问题描述
阅兵式前一天,是国王的生日,大臣们为他准备了一个n×m(1≤n,m≤10000) 的蛋糕。他准备切蛋糕,但他切蛋糕有奇奇怪怪的癖好,他每次只切一刀,切下一个正方形蛋糕。请问它最多能切出多少个正方形蛋糕?


输入描述


第一行一个整数表示测试组数:T(0<T≤1000) 。
每组数据占一行,每行两个整数 n×m(1≤n,m≤10000),表示蛋糕的大小。


输出描述


共 T 行,每行一个整数表示最多能切出的正方形蛋糕数量。


输入样例
2
2 3
2 5
输出样例
3
4
Hint
对于第一组数据,可切出一个 2×2, 两个 1\times 1×1,共 3 个。

对于第一组数据,可切出两个 2×2, 两个 1\times 1×1,共 4个。


思路:模拟切蛋糕的过程就可以

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
#define INF (1ll<<60)-1
using namespace std;
int n,m,T;
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        if(n>m) swap(n,m);
        int num=0;
        while(n && m){
            m-=n;
            num++;
            if(n>m) swap(n,m);
           /// printf("%d %d\n",n,m);
        }
        printf("%d\n",num);
    }
    return 0;
}



King's Phone  
Accepts: 310   Submissions: 2980
 Time Limit: 2000/1000 MS (Java/Others)   Memory Limit: 65536/65536 K (Java/Others)
问题描述
阅兵式上,国王见到了很多新奇东西,包括一台安卓手机。他很快对手机的图形解锁产生了兴趣。
解锁界面是一个3×3 的正方形点阵,第一行的三个点标号 1, 2, 3,第二行的三个点标号 4, 5, 6,第三行的三个点标号 7, 8, 9。密码本身是一段序列,表示经过点的先后顺序,但遵循如下规则:

1. 密码至少经过四个点。

2. 不能重复经过同一个点。

3. 路径上的中间点不能跳过,除非已经被经过(34273427 是合法的,但 37243724 不合法)。

他想设置的密码的长度为正整数 k(1≤k≤9),密码序列为 s1s2...sk(0≤si<INT_MAX),他想知道这个密码序列是否合法,这个问题交给了你。
输入描述
第一行一个整数表示测试组数:T(0<T≤100000) 。


每组数据占一行,每行第一个数 k,设置密码的长度;接着 k 个正整数,之间用空格隔开,表示密码序列 s​1s2...sk。
输出描述
共 T 行。对每组数据,若合法输出 `valid`,否则输出 `invalid`。
输入样例
3
4 1 3 6 2
4 6 2 1 3
4 8 1 6 7
输出样例
invalid
valid
valid
Hint
对于第一组数据,1 到 3 跳过了路径上的点 2,所以不合法。

对于第二组数据,1 到 3 时点 2 已经被经过了,所以合法。

对于第三组数据,8→1→6→7 路径均没有中间点,所以合法。



思路:

1 2 3 

4 5 6

7 8 9

1. 至少经过四个点,当不足四个点的时候 invalid

2. 0<si<10 不满足条件的时候 invalid

3. 处理是否经过中间数的情况  只有 1 3 7 9  或者  2 8 或者 4 6 这些情况


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
#define INF (1ll<<60)-1
using namespace std;
int T,n;
int a[11],vis[10];
int main(){
    scanf("%d",&T);
    while(T--){
        mst(vis,0);
        int flag=0;
        scanf("%d",&n);
        if(n<4) flag=1;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            if(a[i]<1 || a[i]>9) {
                flag=1;
            }
        }
        if(flag){
            cout<<"invalid"<<endl;
            continue;
        }
        vis[a[1]]=1;
        for(int i=2;i<=n;i++){
            if(vis[a[i]]) {
                flag=1;
                break;
            }
            if(a[i]==1 || a[i]==3 || a[i]==7 || a[i]==9){
                if(a[i-1]==1 || a[i-1]==3 || a[i-1]==7 || a[i-1]==9){
                    if(!vis[(a[i]+a[i-1])/2]){
                        flag=1;
                        break;
                    }
                }
            }
            if((a[i]+a[i-1])==10 && !vis[5]){
                flag=1;
                break;
            }
            vis[a[i]]=1;
        }
        if(flag) cout<<"invalid"<<endl;
        else cout<<"valid"<<endl;
    }
    return 0;
}




King's Order 
 Accepts: 381   Submissions: 1361
 Time Limit: 2000/1000 MS (Java/Others)   Memory Limit: 65536/65536 K (Java/Others)
问题描述
国王演讲后士气大增,但此时战争还没有结束,国王时不时要下发命令。

由于国王的口吃并没有治愈,所以传令中可能出现:“让第三军-军-军,到前线去” 这样的命令。由于大洋国在军队中安插了间谍 , 战事紧急,很多时候前线的指挥官不能分清哪些命令真正来自国王。

但国王的命令有一个特点,他每次连续重复的字符最多 33 次. 所以说他的命令中没有:“让第三军-军-军-军 , 到前线去”,但是可以有 :“让第三军-军 , 到前线去” 。

此时将军找到了你,你需要告诉他,给定命令的长度长度为 n,有多少种不同的命令可以是国王发出的 。(也就是求长度为 n 的合格字符串的个数)当然,国王可能说出一句话没有犯任何口吃,就像他那次演讲一样。

为了简化答案,国王的命令中只含有小写英文字母,且对答案输出模 1000000007。

我们认为两个命令如果完全相同那么这两个字符串逐个比较就完全相同。
输入描述
第一行一个整数表示测试组数:T(T≤10)。

每组数据占一行,每行一个正整数 n(n≤2000) 表示字符串的长度。
输出描述
共 TT 行,每行一个整数表示合法的命令数量。
输入样例
2
2
4
输出样例
676
456950
Hint
两个中没有不符合要求的,所以答案为 26×26=676

四个不符合要求的只有 `aaaa` `bbbb` ... `zzzz`总共 26 个

那么答案就是: 26^4-26 = 456950



思路:

动态规划    状态: dp[i][j]  当前长度为i    第i个字符参与进去的重复字符长度为j的种数

当前的dp[i][j]=dp[i][1] + dp[i][2] + dp[i][3]       (1<=j<=3)

dp[i][1] =( dp[i-1][1] + dp[i-1][2] + dp[i-1][3] ) * 25 


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
#define INF (1ll<<60)-1
#define mod 1000000007
using namespace std;
int T,n;
ll dp[2010][4];/// 当前长度为i 第i个字符参与进去的重复字符长度为j的种数
int main(){
    dp[1][1]=26;
    dp[2][1]=26*25;
    dp[2][2]=26;
    dp[3][1]=26*26*25;
    dp[3][2]=26*25;
    dp[3][3]=26;
    for(int i=4;i<=2000;i++){
        dp[i][1]=((dp[i-1][1]+dp[i-1][2]+dp[i-1][3])*25)%mod;
        dp[i][2]=(dp[i][2]+dp[i-1][1])%mod;
        dp[i][3]=(dp[i][3]+dp[i-1][2])%mod;
    }
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        ll ans=0;
        for(int i=1;i<=3;i++) ans=(ans+dp[n][i])%mod;
        printf("%I64d\n",ans);
    }
    return 0;
}


King's Game 
 Accepts: 249   Submissions: 671
 Time Limit: 2000/1000 MS (Java/Others)   Memory Limit: 65536/65536 K (Java/Others)
问题描述
为了铭记历史,国王准备在阅兵的间隙玩约瑟夫游戏。它召来了n(1≤n≤5000) 个士兵,逆时针围成一个圈,依次标号 1,2,3...n。

第一轮第一个人从 1 开始报数,报到 1 就停止且报到 1 的这个人出局。

第二轮从上一轮出局的人的下一个人开始从 1 报数,报到 2 就停止且报到 2 的这个人出局。

第三轮从上一轮出局的人的下一个人开始从 1 报数,报到 3 就停止且报到 3 的这个人出局。

第 n - 1 轮从上一轮出局的人的下一个人开始从 1 报数,报到 n - 1 就停止且报到 n - 1 的这个人出局。

最后剩余的人是幸存者,请问这个人的标号是多少?
输入描述
第一行一个整数表示测试组数:T(0<T≤5000) 。

每组数据占一行,包含一个整数 n,表示 n 个人围成一圈。
输出描述
共 TT 行。对每组数据,输出幸存者的编号。
输入样例
2
2
3
输出样例
2
2
Hint
对于第一组数据,一开始报到 1 的人即标号为 1 的人退出,幸存者是 2 号。

对于第二组数据,一开始报到 1 的人即标号 1 的人退出。接着 2 号报 1,3 号报 2,报到 2 的人即 3 号退出。幸存者是 2 号。


思路  :假设最后剩下的士兵编号为0    从最后一个存活的士兵编号   开始往上找上一层该士兵所处的编号是多少

设f[i] 表示当前第i轮  对于最后一个士兵在该轮所处的编号  

n        剩下的编号 0                           当前只剩下一个士兵 编号为        0                      f[n]=0

n-1     剩下的编号 0 1                        当前只剩下两个士兵 编号分别为 0 1                  f[n-1] = ( f[n] + (n-1) ) % 2

n-2     剩下的编号 0 1 2                    当前只剩下三个士兵 编号分别为 0 1 2               f[n-2] = ( f[n-1] + (n-2) ) % 3 

.         

.         

.         

1         剩下的编号 0 1 2 3 4 ...n-1    当前只剩下n个士兵 编号分别为 0 1 2....n-1         f[1] = ( f[2] + 1 ) % n


答案也就是 f[1] + 1


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
#define INF (1ll<<60)-1
using namespace std;
int T,n;
int dp[5010];
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        dp[n]=0;
        int t=2;
        for(int i=n-1;i>=1;i--){
            dp[i]=(dp[i+1]+i)%t;
            t++;
        }
        cout<<dp[1]+1<<endl;
    }
    return 0;
}


你可能感兴趣的:(BestCoder Round #75)