题目解析
简单签到题,注意转义字符的使用。
题解代码
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("I want to be an ACMer\\n\\n");
return 0;
}
题目解析
读入字符串,从到到尾遍历字符串,统计每个字符出现的次数。排序后将出现次数最多的几个输出即可。
题解代码
#include<stdio.h>
#include<string.h>
#define LL long long
int maxx=0,sum[30],ans[30],tot = 0;
char s[1010];
int MAX(int a,int b)
{
if( a>b ) return a;
else return b;
}
void solve()
{
scanf("%s",s);
int len = strlen(s);
for(int i=0;i<len;i++)
{
sum[ s[i]-'a' ]++;
}
for(int i=0;i<=25;i++) maxx = MAX( maxx , sum[i] );
for(int i=0;i<=25;i++)
{
if( sum[i]==maxx )
{
ans[++tot] = i+'a';
}
}
printf("%c",ans[1]);
for(int i=2;i<=tot;i++)
{
printf(" %c",ans[i]);
}
}
int main()
{
solve();
return 0;
}
题目解析
思路很简单,对每个候选人判断即可,注意票数为0与票数相同的情况。
题解代码
#include <stdio.h>
#include <stdlib.h>
int max(int a,int b)
{
if(a>b)return a;
else return b;
}
void solve()
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
int temp=max(a,max(b,c));
int base=0;
if(a==temp)base++;
if(b==temp)base++;
if(c==temp)base++;
if(base==3)
{
printf("1 1 1\n");
return ;
}
if(base==2)
{
printf("%d %d %d\n",temp-a+1,temp-b+1,temp-c+1);
return ;
}
printf("%d %d %d\n",(temp==a ? 0:temp-a+1),(temp==b ? 0:temp-b+1),(temp==c ? 0:temp-c+1));
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
solve();
}
return 0;
}
题目解析
可以通过去掉数组中的许多个0和其中一个1得到s-1,所以只需要分别计算0和1的数目,记为f0和f1,答案即为 2 f 0 ∗ f 1 2^{f0}*f1 2f0∗f1
题解代码
#include <stdio.h>
#include <math.h>
int main() {
int t;
scanf("%d",&t);
while (t--) {
int n, a[100010];
scanf("%d", &n);
int f0 = 0;
int f1 = 0;
long long sum = 0;
for (int i = 0; i < n; ++i) {
scanf("%d", &a[i]);
sum += a[i];
if (a[i] == 0)
f0++;
if (a[i] == 1)
f1++;
}
printf("%lld\n", (long long) f1 * (long long) pow(2, f0));
}
return 0;
}
题目解析
首先考虑最简单的情况,n个数互不相同且非零,答案为 A n n A_n^n Ann,其次考虑有重复数字的情况,举例说明,如1 1 2 3 3 4,答案为 A 6 6 / ( A 2 2 × A 2 2 ) A_6^6/(A^2_2×A_2^2) A66/(A22×A22)其他情况与此类似,最后考虑有0的情况,0不能在首位,故不考虑重复的情况下,有0时答案为(n – 0的个数)× A n − 1 n − 1 A_{n-1}^{n-1} An−1n−1然后转到第二步即可
故用一个数组记录每个数字出现的个数,按照上面过程模拟即可,标程中已注释
题解代码
#include <stdio.h>
#include <stdlib.h>
int factorial(int n)//求n的阶乘
{
int ans = 1, i;
for (i = 1; i <= n; i++) {
ans *= i;
}
return ans;
}
int main()
{
int num[10] = {0};//表示每个数出现的次数
int n, i, t, ans = 1;
scanf("%d", &n);
for (i = 0; i < n; i++) {
scanf("%d", &t);
num[t]++;//出现次数+1
}
if (num[0]) {//是否有0
ans = (n - num[0]) * factorial(n - 1);//有零
} else {
ans = factorial(n);//无零
}
for (i = 0; i < 10; i++) {
if (num[i]) {
ans /= factorial(num[i]);//消去重复的排列
}
}
printf("%d", ans);
return 0;
}
题目解析
40
%
40\%
40%分数解法: 这部分数据
n
≤
2
n \leq 2
n≤2,那么就很好分类了
当
n
=
=
1
n==1
n==1时,直接输出答案,当
n
=
=
2
n==2
n==2时,直接输出
max
(
a
+
b
,
a
−
b
)
\max( a+b ,a-b )
max(a+b,a−b)
100
%
100\%
100%分数解法: 当我们选好一次操作的
x
x
x和
y
y
y后,会发现
y
≤
0
,
x
+
y
≥
x
−
y
y
≥
0
,
x
+
y
≤
x
−
y
y\leq0 , x+y\geq x-y \\ y\geq0,x+y \leq x-y
y≤0,x+y≥x−yy≥0,x+y≤x−y
那么最后一定是
x
+
∣
y
∣
x + \mid y \mid
x+∣y∣的数值最大,除了第一个数外,每一个数都会有机会成为
x
x
x和
y
y
y中的
y
y
y。所以答案就是
a
n
s
=
a
1
+
∑
i
=
2
n
∣
a
i
∣
ans = a_1 + \sum_{i=2}^n \mid a_i \mid
ans=a1+i=2∑n∣ai∣
但是注意数据范围最后会很大,不用long long的话只能拿到90%分。
题解代码
40 % 40\% 40%分数解法:
#include<stdio.h>//40%分数code
#include<math.h>
int x,y,n,ans;
int MAX(int a,int b) {
if( a>b ) return a;
else return b;
}
void solve() {
scanf("%d",&n);
if( n==1 ) {
scanf("%d",&x);
ans = x;
} else if( n==2 ) {
scanf("%d %d",&x,&y);
ans = MAX( x+y, x-y );
}
printf("%d",ans);
}
int main() {
solve();
return 0;
}
100 % 100\% 100%分数解法:
#include<stdio.h>
#include<math.h>
#define LL long long//最后一个测试点数据量很大,需要long long
LL x,n,ans;
void solve() {
ans = 0;
scanf("%lld",&n);
for(int i=1; i<=n; i++) {
scanf("%lld",&x);
if( i==1 ) ans += x;//第一个数字需要特殊判断
else ans += abs(x);//其余数字直接加绝对值就好
}
printf("%lld",ans);
}
int main() {
solve();
return 0;
}
题目解析
本题主要考察用代码模拟实际问题的能力。对于每个移动方案,先令
c
a
n
=
t
r
u
e
can=true
can=true ,假设它可以满足要求。将移动的操作保存在
o
p
[
N
]
[
2
]
op[N][2]
op[N][2]中;
c
n
t
[
i
]
(
1
≤
i
≤
3
)
cnt[i](1\le i\le 3)
cnt[i](1≤i≤3)记录第
i
i
i根石柱上现在有多少个圆盘; 保存
a
[
i
]
[
N
]
a[i][N]
a[i][N]着第
i
i
i根石柱上所有圆盘的顺序。
初始化令
a
[
1
]
[
i
]
=
n
−
i
+
1
,
c
n
t
[
1
]
=
n
,
c
n
t
[
2
]
=
c
n
t
[
3
]
=
0
a[1][i]=n-i+1,cnt[1]=n,cnt[2]=cnt[3]=0
a[1][i]=n−i+1,cnt[1]=n,cnt[2]=cnt[3]=0。
对于每个从第
f
r
fr
fr根石柱移动到第
t
o
to
to根石柱的操作,若第
f
r
fr
fr根石柱上没有圆盘,那么即发现不合法的操作。
否则,检查第
t
o
to
to根石柱顶端的圆盘是否小于第
f
r
fr
fr根石柱顶端圆盘的大小,若是,则发现不合法。
将第
f
r
fr
fr根石柱顶端圆盘移动到第
t
o
to
to根石柱顶端,修改
c
n
t
[
f
r
]
cnt[fr]
cnt[fr]与
c
n
t
[
t
o
]
cnt[to]
cnt[to] 。
检查完所有的移动操作后,若依然没有发现不合法操作,并且此时所有圆盘都在第三根石柱上,那么这个方案就是满足题意的;否则不满足题意。
题解代码
#include<stdio.h>
#include<stdlib.h>
#define N 10010
int T,n,m,a[4][N],cnt[4],op[N][2];
void solve() {
int can=1;
scanf("%d%d",&n,&m);
for(int i=1; i<=m; i++)
scanf("%d%d",&op[i][0],&op[i][1]);
for(int i=1; i<=n; i++) a[1][i]=n-i+1;
cnt[1]=n;
cnt[2]=0;
cnt[3]=0;
for(int i=1; i<=m; i++) {
int fr=op[i][0],to=op[i][1];
if(cnt[fr]==0) {
can=0;
break;
}
if(cnt[to]>=1&&a[fr][cnt[fr]]>a[to][cnt[to]]) {
can=0;
break;
}
a[to][++cnt[to]]=a[fr][cnt[fr]--];
}
if(can==1&&cnt[1]==0&&cnt[2]==0&&cnt[3]==n)
printf("YES\n");
else printf("NO\n");
}
int main() {
scanf("%d",&T);
while(T--) solve();
}
题目解析
首先来探讨一下怎么求 f ( s ) f(s) f(s),用贪心的策略去考虑的话,对于给定的 s s s和 a a a,从高到低的去遍历 a a a,那么对第 i i i种货币需要的数量为 ⌊ s / 1 0 a i ⌋ \lfloor s/10^{a_i}\rfloor ⌊s/10ai⌋( s s s为减去上一个之后剩下的值),显然遍历过第 i i i中货币后, s s s的新值满足 s < 1 0 a i s<10^{a_i} s<10ai,那么 s s s在 a i − 1 a_{i-1} ai−1所取的值不会超过 1 0 a i / 1 0 a i − 1 − 1 10^{a_i}/10^{a_{i-1}}-1 10ai/10ai−1−1,计算结果中如果没有 − 1 -1 −1,为了达到最少,就可以直接取 a i a_i ai。
那么根据题意来求解 s s s,实际上就是找一个最小的数 s s s使得 f ( s ) > k f(s)>k f(s)>k ,显然 f ( s ) f(s) f(s)的最小值就是 k + 1 k+1 k+1,那么问题转换成用 k + 1 k+1 k+1张货币来构造 s s s了,为了使 s s s的面额最小,对 a a a从小到大遍历,设 n u m num num为剩下的可用支票数(初值为 k + 1 k+1 k+1),对于 a i a_i ai,其选择的数量应为 m i n ( n u m , 1 0 a i / 1 0 a i − 1 − 1 ) min(num,10^{a_i}/10^{a_{i-1}}-1) min(num,10ai/10ai−1−1),前者是所需的最少货币数,后者是最多能拿多少 a i a_i ai,这样就不会破坏 f ( s ) f(s) f(s)的最小值。
题解代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef long long ll;
int t,a[10],n,k;
ll Min(ll a,ll b)
{
if(a>b)return b;
else return a;
}
int main() {
scanf("%d",&t);
while(t--) {
scanf("%d%d",&n,&k);
int tmp;
ll res=0;
for(int i=0; i<n; i++) {
scanf("%d",&a[i]);
tmp=1;
while(a[i]--)tmp*=10;
a[i]=tmp;
}
k++;
for(int i=0; i<n; i++) {
tmp=k;
if(i+1<n)tmp=Min(tmp,a[i+1]/a[i]-1);//最后一个除外,把剩余的都给最后一个
res+=a[i]*1ll*tmp;
k-=tmp;
}
printf("%lld\n",res);
}
return 0;
}
题目解析
由于在所有种类的鞋子了,只有一种是奇数,其他都是偶数,利用异或自反性可以得到答案。
题解代码
#include <stdio.h>
#define ll long long
signed main() {
int T,i,n;
scanf("%d",&T);
while(T--)
{
ll x,ans=0;
scanf("%d",&n);
for(i=1;i<=n;i++) scanf("%lld",&x),ans^=x;
printf("%lld\n",ans);
}
return 0;
}
题目解析
这道题可以从数或几何的角度去想。
正确的结果是: r 1 / n ( c o s θ + 2 k π n + i s i n θ + 2 k π n ) , k = 0 , … , n − 1 r^{1/n}\big(cos\frac{\theta+2k\pi}{n}+isin\frac{\theta+2k\pi}{n}\big),k=0,\dots,n-1 r1/n(cosnθ+2kπ+isinnθ+2kπ),k=0,…,n−1
要用极坐标形式下解决这个问题,由于两个复数相乘在复平面上表现为它们的模相乘,幅角相加,即 ( r 1 ( c o s θ 1 + i s i n θ 1 ) ) ( r 2 ( c o s θ 2 + i s i n θ 2 ) ) = r 1 r 2 ( c o s ( θ 1 + θ 2 ) + i s i n ( θ 1 + θ 2 ) ) \big(r_1(cos\theta_1+isin\theta_1)\big)\big(r_2(cos\theta_2+isin\theta_2)\big)=r_1r_2\big(cos(\theta_1+\theta_2)+isin(\theta_1+\theta_2)\big) (r1(cosθ1+isinθ1))(r2(cosθ2+isinθ2))=r1r2(cos(θ1+θ2)+isin(θ1+θ2)),因此在模 r r r上和幅角上的运算是分开的。要求一个数的 n n n次方根,如果依然用这种极坐标的表示法,那么这些根的模一定是 r 1 / n r^{1/n} r1/n(开方运算)。在幅角上,根的幅角应该为 θ + 2 k π n , k = 0 , … , n − 1 \frac{\theta+2k\pi}{n},k=0,\dots,n-1 nθ+2kπ,k=0,…,n−1(除法运算),正好 n n n个,加 2 k π 2k\pi 2kπ的原因就是这样这些根的 n n n次方辐角为 θ + 2 k π \theta+2k\pi θ+2kπ,而 c o s ( θ + 2 k π ) = θ , s i n cos(\theta+2k\pi)=\theta,sin cos(θ+2kπ)=θ,sin同,它们的 n n n次方的幅角是不变的,也就是同一个复数,而这样不同的根能取 0 , 1 , … , n − 1 0,1,\dots,n-1 0,1,…,n−1一共 n n n个(若 k = n k=n k=n则与 k = 0 k=0 k=0的副角相同,代表同一个复数),因此让 k k k从0取到n-1顺序循环运算,再换成普通形式就可得到数值解。
题解代码
#include <stdio.h>
#include <math.h>
double Pi=acos(-1);
int main()
{
double a,b;
int n;
while(scanf("%lf%lf%d",&a,&b,&n) && n!=0)
{
double module=sqrt(a*a+b*b);
double r=pow(module,1.0/n);
double x=acos(a/module);
for(int k=0;k<n;k++)
{
printf("(%.7f)+i(%.7f)\n",r*cos((x+2*k*Pi)/n),r*sin((x+2*k*Pi)/n));
}
}
}