阅兵式前一天,是国王的生日,大臣们为他准备了一个 n×m(1≤n,m≤10000) 的蛋糕。他准备切蛋糕,但他切蛋糕有奇奇怪怪的癖好,他每次只切一刀,切下一个正方形蛋糕。请问它最多能切出多少个正方形蛋糕?
第一行一个整数表示测试组数:T(0<T≤1000) 。 每组数据占一行,每行两个整数 n×m(1≤n,m≤10000),表示蛋糕的大小。
共 T 行,每行一个整数表示最多能切出的正方形蛋糕数量。
2 2 3 2 5
3 4
对于第一组数据,可切出一个 2×2, 两个 1×1,共 3 个。 对于第一组数据,可切出两个 2×2, 两个 1×1,共 4个。
来自官方的题解:显然这很像求最大公约数的过程嘛,看这张神图:
所以每次 gcd 的时候累加答案即可,复杂度 O(logmax(n,m)T)。
当然你要是循环减应该也放过了。
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define LL __int64 const int maxm=1e5+10; int main() { int t; scanf("%d",&t); while(t--) { int n,m; scanf("%d%d",&n,&m); if(m<n) swap(m,n); int sum=0; while(m&&n) { if(m==1||n==1) { if(m==1) sum+=n; else sum+=m; break; } sum+=m/n; m=m%n; if(m<n) swap(m,n); } printf("%d\n",sum); } return 0; }
King's Phone
Accepts: 310Submissions: 2980Time 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. 路径上的中间点不能跳过,除非已经被经过(3427 是合法的,但 3724 不合法)。 他想设置的密码的长度为正整数 k(1≤k≤9),密码序列为 s1s2...sk(0≤si<INT_MAX),他想知道这个密码序列是否合法,这个问题交给了你。输入描述第一行一个整数表示测试组数:T(0<T≤100000) 。 每组数据占一行,每行第一个数 k,设置密码的长度;接着 k 个正整数,之间用空格隔开,表示密码序列 s1s2...sk。输出描述共 T 行。对每组数据,若合法输出 `valid`,否则输出 `invalid`。
输入样例3 4 1 3 6 2 4 6 2 1 3 4 8 1 6 7输出样例invalid valid validHint对于第一组数据,1 到 3 跳过了路径上的点 2,所以不合法。 对于第二组数据,1 到 3 时点 2 已经被经过了,所以合法。 对于第三组数据,8→1→6→7 路径均没有中间点,所以合法。一个简单的模拟题,首先判断序列长度是否合法,接着判断 si 是否在 [1,9],最后扫一遍看看有没有重复以及跨过中间点的情况即可。
复杂度:O(nT)。
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define LL __int64 const int maxm=20; int a[maxm]; int vis[maxm]; int main() { int t; scanf("%d",&t); while(t--) { int n; scanf("%d",&n); memset(vis,0,sizeof(vis)); int ok=0; for(int i=0; i<n; i++) { scanf("%d",&a[i]); if(a[i]>9||a[i]<=0) ok=1; } if(n<4||n>9) ok=1; if(ok) printf("invalid\n"); else { vis[a[0]]=1; for(int i=1; i<n; i++) { if(vis[a[i]]==1) { ok=1; break; } else { vis[a[i]]=1; if(a[i]==1&&((a[i-1]==3&&vis[2]==0)||(a[i-1]==7&&vis[4]==0)||(a[i-1]==9&&vis[5]==0))) { ok=1; break; } else if(a[i]==2&&a[i-1]==8&&vis[5]==0) { ok=1; break; } else if(a[i]==3&&((a[i-1]==1&&vis[2]==0)||(a[i-1]==7&&vis[5]==0)||(a[i-1]==9&&vis[6]==0))) { ok=1; break; } else if(a[i]==4&&a[i-1]==6&&vis[5]==0) { ok=1; break; } else if(a[i]==6&&a[i-1]==4&&vis[5]==0) { ok=1; break; } else if(a[i]==7&&((a[i-1]==3&&vis[5]==0)||(a[i-1]==1&&vis[4]==0)||(a[i-1]==9&&vis[8]==0))) { ok=1; break; } else if(a[i]==8&&a[i-1]==2&&vis[5]==0) { ok=1; break; } else if(a[i]==9&&((a[i-1]==7&&vis[8]==0)||(a[i-1]==3&&vis[6]==0)||(a[i-1]==1&&vis[5]==0))) { ok=1; break; } } } if(ok) printf("invalid\n"); else printf("valid\n"); } } return 0; }King's Order
Accepts: 381Submissions: 1361Time Limit: 2000/1000 MS (Java/Others)Memory Limit: 65536/65536 K (Java/Others)来自官方题解:问题描述国王演讲后士气大增,但此时战争还没有结束,国王时不时要下发命令。 由于国王的口吃并没有治愈,所以传令中可能出现:“让第三军-军-军,到前线去” 这样的命令。由于大洋国在军队中安插了间谍 , 战事紧急,很多时候前线的指挥官不能分清哪些命令真正来自国王。但国王的命令有一个特点,他每次连续重复的字符最多 3 次. 所以说他的命令中没有:“让第三军-军-军-军 , 到前线去”,但是可以有 :“让第三军-军 , 到前线去” 。 此时将军找到了你,你需要告诉他,给定命令的长度长度为 n,有多少种不同的命令可以是国王发出的 。(也就是求长度为 n 的合格字符串的个数)当然,国王可能说出一句话没有犯任何口吃,就像他那次演讲一样。 为了简化答案,国王的命令中只含有小写英文字母,且对答案输出模 1000000007。 我们认为两个命令如果完全相同那么这两个字符串逐个比较就完全相同。输入描述第一行一个整数表示测试组数:T(T≤10)。 每组数据占一行,每行一个正整数 n(n≤2000) 表示字符串的长度。输出描述共 T 行,每行一个整数表示合法的命令数量。
输入样例2 2 4输出样例676 456950Hint两个中没有不符合要求的,所以答案为 26×26=676 四个不符合要求的只有 `aaaa` `bbbb` ... `zzzz`总共 26 个 那么答案就是: 264−26=456950数一个长度为 n 的序列 , 并且序列中不能出现长度大于 3 的连续的相同的字符 , 这玩意就是一个数位DP嘛。 定义 d[i][j][k] 为处理完 i 个字符 , 结尾字符为 ′a′+j , 结尾部分已重复出现了 k 次的方案数。 刷表转移一下就好啦。
复杂度:O(26∗26∗nT)
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define LL __int64 const int maxm=2e3+10; const LL MOD = 1e9+7; LL dp[maxm][300][5]; LL sum(LL a,LL b) { return (a+b)%MOD; } void M() { memset(dp,0,sizeof(dp)); for(int i=1; i<=26; i++) { dp[1][i][1] = 1; } for(int i=2; i<=2000; i++) { for(int j=1; j<=26; j++) { for(int k=1; k<=26; k++) { if(j!=k) { for(int q=1; q<=3; q++) { dp[i][j][1] = sum(dp[i][j][1],dp[i-1][k][q]); } } else { dp[i][j][2] = sum(dp[i][j][2],dp[i-1][k][1]); dp[i][j][3] = sum(dp[i][j][3],dp[i-1][k][2]); } } } } } int main() { int T; M(); scanf("%d",&T); while(T--) { int n; scanf("%d",&n); LL ans = 0; for(int i=1; i<=26; i++) { for(int j=1; j<=3; j++) { ans = sum(ans,dp[n][i][j]); } } printf("%I64d\n",ans); } return 0; }