题目链接:http://sustoj.com/JudgeOnline/contest.php?cid=1035
问题 A: 三角形的面积
三角形成立的条件是:任意两边大于第三边
已知三边求面积:
c
o
s
A
=
b
2
+
c
2
−
a
2
2
b
c
cos A=\frac{b^2+c^2-a^2}{2bc}
cosA=2bcb2+c2−a2
S
=
1
2
b
c
s
i
n
A
S=\frac{1}{2} b c sinA
S=21bcsinA
AC code
#include <stdio.h>
#include <math.h>
double a,b,c;
double A;
double ans;
int main(){
int t;
scanf("%d", &t);
while(t--) {
scanf("%lf %lf %lf", &a, &b, &c);
if(a+b-c<=0||a+c-b<=0||b+c-a<=0){
printf("-1\n");
}else{
A=acos((b*b+c*c-a*a)/(b*c*2.0));
ans=(sin(A)*b*c)/2.0;
printf("%.3lf\n", ans);
}
if(t!=0) printf("\n");
}
return 0;
}
问题 B: 小辉辉玩积木
f
[
n
]
f[n]
f[n]最后一步添加的只有两种情况,要么是一条竖的方格或者是两条横着的方格
如图:
可以看出来剩下白色的就是
f
[
n
−
1
]
和
f
[
n
−
2
]
f[n-1]和f[n-2]
f[n−1]和f[n−2]
所以
f
[
n
]
=
f
[
n
−
1
]
+
f
[
n
−
2
]
(
n
>
2
)
f[n]=f[n-1]+f[n-2] (n>2)
f[n]=f[n−1]+f[n−2](n>2)
结论:
f
[
n
]
=
{
1
n
=
1
2
n
=
2
f
[
n
−
1
]
+
f
[
n
−
2
]
n
>
2
f[n]=\begin{cases} 1 & n=1\\ 2 & n=2\\ f[n-1]+f[n-2]&n>2 \end{cases}
f[n]=⎩⎪⎨⎪⎧12f[n−1]+f[n−2]n=1n=2n>2
AC code
#include <stdio.h>
#define maxn 55
#define ll long long
ll f[maxn];
void init(){
f[1]=1;
f[2]=2;
for(int i=3;i<51;i++){
f[i]=f[i-1]+f[i-2];
}
return ;
}
int main(){
int n;
init();
while(~scanf("%d", &n)){
printf("%lld\n", f[n]);
}
return 0;
}
问题 C: 括号匹配
用栈来模拟括号匹配
遇到 ‘(’ 就进栈
遇到 ‘)’ 就出栈
要是最后栈空了,就输出Yes
要是要出栈时栈空了,就输出No
PS: 输入时要用gets函数,因为中间有空格
AC code
#include <cstdio>//简单版
#include <cstring>
using namespace std;
#define maxn 1000000
char a[maxn];
int main(){
while(gets(a)){
int num=0;
bool b=false;
int len=strlen(a);
for(int i=0;i<len;i++){
if(a[i]=='(') num++;
if(a[i]==')')num--;
if(num<0){
b=true;
break;
}
}
if(num!=0) b=true;
if(!b) printf("Yes\n");
else printf("No\n");
}
return 0;
}
#include <cstdio>//stack版
#include <stack>
#include <cstring>
using namespace std;
#define maxn 100000
char a[maxn];
stack<char> s;
int main(){
while(gets(a)){
while(!s.empty()) s.pop();//清空栈
bool ans=false;
int len=strlen(a);
for(int i=0;i<len;i++){
if(a[i]=='(') s.push('(');
else if(i!=len-1&&a[i]==')'&&s.empty()) {ans=true;break;}
else if(a[i]==')'&&!s.empty()) s.pop();
}
if(!s.empty()) ans=true;
if(ans) printf("No\n");
else printf("Yes\n");
}
return 0;
}
问题 D: 礼物
先找到B,输出B的左边或者右边有多少括号没有匹配上
PS:因为题目上说保证括号匹配,所以B左边和右边,没有匹配的个数是一样的
AC code
#include <cstdio>//简单版
#include <cstring>
using namespace std;
#define maxn 1000000
char a[maxn];
int main(){
while(gets(a)){
int num=0;
int len=strlen(a);
int lenr=0;
for(int i=0;i<len;i++){
if(a[i]=='B'){
lenr=i;
break;
}
}
for(int i=0;i<lenr;i++){
if(a[i]=='(') num++;
if(a[i]==')')num--;
}
if(num<0) num=-num;
printf("%d\n", num);
}
return 0;
}
#include <cstdio>//stack版
#include <stack>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 100000
char a[maxn];
stack<char> s1;
stack<char> s2;
int main(){
while(gets(a)){
while(!s1.empty()) s1.pop();//清空栈
while(!s2.empty()) s2.pop();//清空栈
int len=strlen(a);
int lenr=0;
for(int i=0;i<len;i++){
if(a[i]=='B'){
lenr=i;
break;
}
}
int ans=0;
for(int i=0;i<lenr;i++){
if(a[i]=='(') s1.push('(');
if(a[i]==')'&&!s1.empty()) s1.pop();
}
for(int i=0;i<lenr;i++){
if(a[i]==')') s2.push('(');
if(a[i]=='('&&!s2.empty()) s2.pop();
}
printf("%d\n", max(s1.size(),s2.size()));
}
return 0;
}
问题 E: 单身狗的寻觅
因为
n
<
1
0
8
n<10^8
n<108 数组存不下,要用O(1)的算法
用贪心的思想,要是前面和现在这个数字匹配,就ans++,
不匹配就跳过
AC code
#include <cstdio>//简单版
#include <cstring>
using namespace std;
#define maxn 1000000
int main(){
int n,a,b;
while(~scanf("%d\n", &n)){
int ans=0;
scanf("%d", &a);
for(int i=1;i<n;i++){
if(i%2==1){
scanf("%d", &b);
if(a%2==0&&b%2==1){
ans++;
b=-1;
}
if(a%2==1&&b%2==0){
ans++;
b=-1;
}
}else{
scanf("%d", &a);
if(a%2==0&&b%2==1){
ans++;
a=-1;
}
if(a%2==1&&b%2==0){
ans++;
a=-1;
}
}
}
printf("%d\n", ans);
}
return 0;
}
#include <cstdio>//滚动数组+位运算版
#include <stack>
#include <cstring>
#include <algorithm>
using namespace std;
int a[2];
int main(){
int n;
while(~scanf("%d", &n)){
int ans=0;
scanf("%d", &a[0]);
a[0]=a[0]&1;
for(int i=1;i<n;i++){
scanf("%d", &a[i&1]);
a[i&1]=a[i&1]&1;
if(a[0]==1&&a[1]==0){
a[0]=-1;
a[1]=-1;
ans++;
}
if(a[0]==0&&a[1]==1){
a[0]=-1;
a[1]=-1;
ans++;
}
}
printf("%d\n", ans);
}
return 0;
}
//位运算不懂的请自行百度
问题 F: Brave Game
因为第一步可以取走
1...
m
1...m
1...m个石子,所以要是
n
≤
m
n≤m
n≤m 则第一个人必赢
所以
1
到
m
+
1
1到m+1
1到m+1就是第一个人的必胜态
当
n
=
m
+
1
n=m+1
n=m+1时,无论第一个第一次人取多少,第二个总能在第二次取完
所以m+1就是第二个人的必胜态
接来下就是看能不能转换到各自的必胜态,当然自己的必胜态就是对手的必败态
例如
n
=
m
+
3
n=m+3
n=m+3
先手可以取2两剩余
m
+
1
m+1
m+1
这样先手就变成了后手了
结论:
后手必胜
n
%
(
m
+
1
)
=
0
n \% (m+1)=0
n%(m+1)=0
AC code
#include <cstdio>
#include <stack>
#include <cstring>
#include <algorithm>
using namespace std;
int main(){
int t,n,m;
scanf("%d", &t);
while(t--){
scanf("%d %d", &n, &m);
if(n%(m+1)!=0) printf("first\n");
else printf("second\n");
}
return 0;
}
问题 G: 赛马
经典的贪心问题
若渣渣最快的马比悠悠的最马快并且渣渣最慢的马也比悠悠最慢的马慢,那就拿悠悠最慢的马去换渣渣最快的马
要是悠悠最快的马比渣渣的马快 那就拿悠悠最快的马去换渣渣的最马快
要是悠悠最慢的马比渣渣的马慢 那就拿悠悠最慢的马去换渣渣的最马慢
剩下的就是那悠悠最慢的马消耗掉渣渣最快的马
AC code
#include <cstdio>
#include <stack>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 1010
int a[maxn],b[maxn];
int n;
bool cmp(int a,int b){
return a>b;
}
int main(){
while(~scanf("%d", &n)&&n){
int ans=0;
for(int i=0;i<n;i++){
scanf("%d", &a[i]);
}
for(int i=0;i<n;i++){
scanf("%d", &b[i]);
}
sort(a,a+n,cmp);
sort(b,b+n,cmp);
int al=0,bl=0;
int ar=n-1,br=n-1;
for(int i=0;i<n;i++){
if(a[al]<b[bl]&&a[ar]<b[br]){
ans--;
ar--;
bl++;
}else if(a[ar]>b[br]){
ans++;
ar--;
br--;
}else if(a[al]>b[bl]){
ans++;
al++;
bl++;
}else {
if(a[ar]<b[bl]){
ans--;
}else if(a[ar]>b[bl]){
ans++;
}
ar--;
bl++;
}
}
printf("%d\n", ans);
}
return 0;
}
问题 H: 渣渣辉别墅前的水滩
经典的 DFS 例题
AC code
#include <bits/stdc++.h>
using namespace std;
#define maxn 1000
char mp[maxn][maxn];
int n,m;
void dfs(int x,int y){
mp[x][y]='0';
if(x-1>=0&&mp[x-1][y]=='W') dfs(x-1,y);
if(x+1<n&&mp[x+1][y]=='W') dfs(x+1,y);
if(y-1>=0&&mp[x][y-1]=='W') dfs(x,y-1);
if(y+1<m&&mp[x][y+1]=='W') dfs(x,y+1);
if(x-1>=0&&y-1>=0&&mp[x-1][y-1]=='W') dfs(x-1,y-1);
if(x+1<n&&y+1<m&&mp[x+1][y+1]=='W') dfs(x+1,y+1);
if(y-1>=0&&x+1<n&&mp[x+1][y-1]=='W') dfs(x+1,y-1);
if(y+1<m&&x-1>=0&&mp[x-1][y+1]=='W') dfs(x-1,y+1);
}
int main(){
while(~scanf("%d %d", &n, &m)&&n&&m){
int ans=0;
for(int i=0;i<n;i++){
scanf("%s", mp[i]);
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(mp[i][j]=='W'){
dfs(i,j);
ans++;
}
}
}
printf("%d\n", ans);
}
return 0;
}
问题 I: 平面迷宫
经典的BFS例题
AC code
#include <bits/stdc++.h>
using namespace std;
#define maxn 1000
char mp_c[maxn][maxn];
int mp[maxn][maxn];
int n,m;
struct node {
int x,y;
};
int bx,by;
int ex,ey;
void init(){
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(mp_c[i][j]=='S'){
mp[i][j]=1;
bx=i;
by=j;
}else if(mp_c[i][j]=='E'){
mp[i][j]=0;
ex=i;
ey=j;
}else if(mp_c[i][j]=='#') mp[i][j]=-1;
else mp[i][j]=0;
}
}
}
queue<node> q;
int bfs(){
node a,b;
int x,y;
a.x=bx;
a.y=by;
q.push(a);
while(!q.empty()){
b=q.front();
q.pop();
x=b.x;
y=b.y;
if(x==ex&&y==ey) return mp[x][y];
if(x-1>=0&&mp[x-1][y]==0){
mp[x-1][y]=mp[x][y]+1;
a.x=x-1;
a.y=y;
q.push(a);
}
if(x+1<n&&mp[x+1][y]==0){
mp[x+1][y]=mp[x][y]+1;
a.x=x+1;
a.y=y;
q.push(a);
}
if(y-1>=0&&mp[x][y-1]==0){
mp[x][y-1]=mp[x][y]+1;
a.x=x;
a.y=y-1;
q.push(a);
}
if(y+1<m&&mp[x][y+1]==0){
mp[x][y+1]=mp[x][y]+1;
a.x=x;
a.y=y+1;
q.push(a);
}
}
return -1;
}
int main(){
while(~scanf("%d %d", &n, &m)){
for(int i=0;i<n;i++){
scanf("%s", mp_c[i]);
}
init();
int ans=bfs();
if(ans==-1) printf("Trapped!\n");
else printf("Escaped in %d minute(s).\n", ans-1);
}
return 0;
}
问题 J: 炒鸡蛋简单的A+B
经典大数加法
直接模拟手算加就行
AC code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 1000000
char* strrev(char* s)
{
/* h指向s的头部 */
char* h = s;
char* t = s;
char ch;
/* t指向s的尾部 */
while(*t++){};
t--; /* 与t++抵消 */
t--; /* 回跳过结束符'\0' */
/* 当h和t未重合时,交换它们所指向的字符 */
while(h < t)
{
ch = *h;
*h++ = *t; /* h向尾部移动 */
*t-- = ch; /* t向头部移动 */
}
return(s);
}
void num_plus(char *a,char *b){
char aa[maxn];
memset(aa,0,sizeof aa);
int lena=strlen(a);
int lenb=strlen(b);
strrev(a);
strrev(b);
int len=max(lena,lenb);
int yu=0;
int i=0;
while(1){
if(i<lena&&i<lenb){
yu=(a[i]-'0')+(b[i]-'0')+yu;
aa[i]=yu%10+'0';
yu=yu/10;
}else if(i<lena){
yu=(a[i]-'0')+yu;
aa[i]=yu%10+'0';
yu=yu/10;
}else if(i<lenb){
yu=(b[i]-'0')+yu;
aa[i]=yu%10+'0';
yu=yu/10;
}else if(yu!=0){
aa[i]=yu%10+'0';
yu=yu/10;
}else break;
++i;
}
strrev(aa);
printf("%s\n", aa);
return ;
}
char a[maxn],b[maxn];
int main(){
while(~scanf("%s %s", a, b)){
num_plus(a,b);
}
return 0;
}
//因为学校OJ后台<cstring>中没有strrev()这个函数,所以要手动添strrev()的源码
问题 K: 求斐波那契数列
经典的矩阵快速幂
AC code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define MOD 1000000009
struct matrix{//矩阵快速幂
ll m[2][2];
};
matrix matrix_multi(matrix a,matrix b){
matrix tmp;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++){
tmp.m[i][j]=0;
for(int k=0;k<2;k++)
tmp.m[i][j]=((tmp.m[i][j])% (MOD) + (a.m[i][k]*b.m[k][j]+MOD)% (MOD)) % (MOD);
}
return tmp;
}
matrix matrix_pow(matrix a,matrix b,ll n){
while(n>0){
if(n&1) b=matrix_multi(a,b);
a=matrix_multi(a,a);
n>>=1;
}
return b;
}
int main(){
matrix a,b,ans;
ll n;
a.m[0][0]=1; a.m[0][1]=0;
a.m[1][0]=1; a.m[0][1]=0;
b.m[0][0]=1; b.m[0][1]=1;
b.m[1][0]=1; b.m[1][1]=0;
while(~scanf("%lld", &n)){
ans=matrix_pow(b,a,n-2);
printf("%lld\n", ans.m[0][0]);
}
return 0;
}
问题 L: 矩阵快速幂+欧拉扩展
我们可以将fn拆乘 (x个f1相乘)乘以(y个f2相乘)乘以(z个f3相乘)乘以 pow(c,k)
f3 f2 f1
1 0 0 1
2 0 1 0
3 1 0 0
4 1 1 1
5 2 2 1
6 4 3 2
7 7 6 4
从第四行开始
第n行的f1系数等于 第(n-1)行f1系数+第(n-2)行f1系数+第(n-3)行f1系数
第n行的f2系数等于 第(n-1)行f2系数+第(n-2)行f2系数+第(n-3)行f2系数
第n行的f3系数等于 第(n-1)行f3系数+第(n-2)行f3系数+第(n-3)行f3系数
以f1为例
矩阵可以写成
1 1 1 4 0 0
1 0 0 * 2 0 0
0 1 1 1 0 0
接下来就是求 pow(c,k);
1 1
2 1
3 1
4 pow(c,2)
5 pow(c,4)*pow(c,2)
6 pow(c,6)*pow(c,4)*pow(c,2)*pow(c,2)
7 pow(c,8)*pow(c,4)*pow(c,2)*pow(c,2) * pow(c,4)*pow(c,2) * pow(c,2)
从第四行开始
第n行为 第(n-1)行结果*第(n-2)行结果*第(n-3)行结果*pow(c,2*n-6)
矩阵可以写成
1 1 1 2 -6 14 0 0 0 0
1 0 0 0 0 6 0 0 0 0
0 1 0 0 0 * 2 0 0 0 0
0 0 0 1 1 7 0 0 0 0
0 0 0 0 1 1 0 0 0 0
为什么要在矩阵相乘里面要MOD-1呢?
因为矩阵算出来的
x
,
y
,
z
,
k
x, y, z, k
x,y,z,k 意思是
f
1
x
,
f
2
y
,
f
3
z
,
c
k
f_1^x, f_2^y, f_3^z, c^k
f1x,f2y,f3z,ck
又因欧拉定理的推论:
所以最终结果是
(
f
1
(
x
%
M
O
D
−
1
)
×
f
2
y
%
M
O
D
−
1
×
f
1
z
%
M
O
D
−
1
×
c
k
%
M
O
D
−
1
)
%
M
O
D
(f_1^{(x\%MOD-1)}\times f_2^{y\%MOD-1}\times f_1^{z\%MOD-1}\times c^{k\%MOD-1})\%MOD
(f1(x%MOD−1)×f2y%MOD−1×f1z%MOD−1×ck%MOD−1)%MOD
AC code
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define ll long long
const ll MOD = 1e9 + 7;
struct matrix{//矩阵快速幂
ll m[5][5];
};
ll pow(ll x,ll n,ll mod){//快速幂
ll res=1;
while(n>0){
if(n%2==1){
res=res*x;
res=res%mod;
}
x=x*x;
x=x%mod;
n>>=1;
}
return res;
}
matrix matrix_multi(matrix a,matrix b){//矩阵相乘
matrix tmp;
for(int i=0;i<5;i++)
for(int j=0;j<5;j++){
tmp.m[i][j]=0;
for(int k=0;k<5;k++)
tmp.m[i][j]=((tmp.m[i][j])% (MOD-1) + (a.m[i][k]*b.m[k][j]+MOD-1)% (MOD-1)) % (MOD-1);
}
return tmp;
}
matrix matrix_pow(matrix a,matrix b,ll n){//矩阵快快速幂
while(n>0){
if(n&1) b=matrix_multi(a,b);
a=matrix_multi(a,a);
n>>=1;
}
return b;
}
ll ff3(ll f3, ll n){
if(n==4) return pow(f3,1,MOD);
if(n==5) return pow(f3,2,MOD);
if(n==6) return pow(f3,4,MOD);
matrix a,b;
memset(a.m,0,sizeof a.m);
memset(b.m,0,sizeof b.m);
a.m[0][0]=1; a.m[0][1]=1; a.m[0][2]=1;
a.m[1][0]=1; a.m[1][1]=0; a.m[1][2]=0;
a.m[2][0]=0; a.m[2][1]=1; a.m[2][2]=0;
b.m[0][0]=4; b.m[0][1]=0; b.m[0][2]=0;
b.m[1][0]=2; b.m[1][1]=0; b.m[1][2]=0;
b.m[2][0]=1; b.m[2][1]=0; b.m[2][2]=0;
matrix ans=matrix_pow(a,b,n-6);
return pow(f3,ans.m[0][0],MOD);
}
ll ff2(ll f2,ll n){
if(n==4) return pow(f2,1,MOD);
if(n==5) return pow(f2,2,MOD);
if(n==6) return pow(f2,3,MOD);
matrix a,b;
memset(a.m,0,sizeof a.m);
memset(b.m,0,sizeof b.m);
a.m[0][0]=1; a.m[0][1]=1; a.m[0][2]=1;
a.m[1][0]=1; a.m[1][1]=0; a.m[1][2]=0;
a.m[2][0]=0; a.m[2][1]=1; a.m[2][2]=0;
b.m[0][0]=3; b.m[0][1]=0; b.m[0][2]=0;
b.m[1][0]=2; b.m[1][1]=0; b.m[1][2]=0;
b.m[2][0]=1; b.m[2][1]=0; b.m[2][2]=0;
matrix ans=matrix_pow(a,b,n-6);
return pow(f2,ans.m[0][0],MOD);
}
ll ff1(ll f1,ll n){
if(n==4) return pow(f1,1,MOD);
if(n==5) return pow(f1,1,MOD);
if(n==6) return pow(f1,2,MOD);
matrix a,b;
memset(a.m,0,sizeof a.m);
memset(b.m,0,sizeof b.m);
a.m[0][0]=1; a.m[0][1]=1; a.m[0][2]=1;
a.m[1][0]=1; a.m[1][1]=0; a.m[1][2]=0;
a.m[2][0]=0; a.m[2][1]=1; a.m[2][2]=0;
b.m[0][0]=2; b.m[0][1]=0; b.m[0][2]=0;
b.m[1][0]=1; b.m[1][1]=0; b.m[1][2]=0;
b.m[2][0]=1; b.m[2][1]=0; b.m[2][2]=0;
matrix ans=matrix_pow(a,b,n-6);
return pow(f1,ans.m[0][0],MOD);
}
ll cc(ll c,ll n){
if(n==4) return pow(c,2,MOD);
if(n==5) return pow(c,6,MOD);
if(n==6) return pow(c,14,MOD);
matrix a,b;
memset(a.m,0,sizeof a.m);
memset(b.m,0,sizeof b.m);
b.m[0][0]=14;
b.m[1][0]=6;
b.m[2][0]=2;
b.m[3][0]=7;
b.m[4][0]=1;
a.m[0][0]=1; a.m[0][1]=1; a.m[0][2]=1; a.m[0][3]=2; a.m[0][4]=-6;
a.m[1][0]=1; a.m[1][1]=0; a.m[1][2]=0; a.m[1][3]=0; a.m[1][4]=0;
a.m[2][0]=0; a.m[2][1]=1; a.m[2][2]=0; a.m[2][3]=0; a.m[2][4]=0;
a.m[3][0]=0; a.m[3][1]=0; a.m[3][2]=0; a.m[3][3]=1; a.m[3][4]=1;
a.m[4][0]=0; a.m[4][1]=0; a.m[4][2]=0; a.m[4][3]=0; a.m[4][4]=1;
matrix ans=matrix_pow(a,b,n-6);
return pow(c,ans.m[0][0],MOD);
}
void solve(){
ll n,f1,f2,f3,c;
scanf("%lld %lld %lld %lld %lld", &n, &f1, &f2, &f3, &c);
if(n==1){
printf("%lld\n", f1);
return ;
}
if(n==2){
printf("%lld\n", f2);
return ;
}
if(n==3){
printf("%lld\n", f3);
return ;
}
ll anss=1;
anss=( anss * ff1(f1,n))%MOD;
anss=( anss * ff2(f2,n))%MOD;
anss=( anss * ff3(f3,n))%MOD;
anss=( anss * cc(c,n))%MOD;
printf("%lld\n", anss);
return ;
}
int main(){
solve();
return 0;
}