A
题目描述
C语言函数,数学函数,傻傻分不清楚~~
题目很简单,我们定义F(x)是满足x取余a乘b的积等于0(即:x%(a*b)==0)这样的a,b的组数。现在给你一个n,你需要求出 F(n)。
比如说当n=4时,a b分别可以是——1*1、1*2、1*4、2*1、2*2、4*1,共6种情况,所以F(4) = 6。
输入
多组输入(不会超过200组)
每组测试数据输入一个整数n (1 <= n <= 10^8)
输出
每组测试数据输出 Case x: y ,x 表示第x组测试数据,y表示F(n)的值,细节参考样例。
样例输入
1
2
3
4
样例输出
Case 1: 1
Case 2: 3
Case 3: 3
Case 4: 6
#include <cstdio>
#include <cstring>
#include <cmath>
#define maxn 10009
using namespace std;
int a[maxn+10];
int prime[maxn+10],p;
void init_p(){
p=0;
memset(a,0,sizeof(a));
for(int i=2;i<maxn;i++){
if(a[i]==0)prime[p++]=i;
for(int j=1;j<p&&prime[j]*i<maxn;j++){
a[i*prime[j]]=1;
if(i%prime[j]==0)break;
}
}
}
int main(){
init_p();
int cas=1;
long long n;
while(scanf("%lld",&n)!=-1){
memset(a,0,sizeof(a));
for(int i=0;i<p;i++){
while(n%prime[i]==0){
a[i]++;
n/=prime[i];
}
}
long long ans = ((n==1)?n:3),t;
for(int i=0;i<p;i++){
t=(long long)(a[i]+2)*(a[i]+1)/2;
ans*=t;
}
printf("Case %d: %lld\n",cas++,ans);
}
return 0;
}
/**
一个分解因数题,根据唯一分解定理,任何一个数可以分解成 p1^e1*p2^e2*p3^e3...(pi为素数,ei为指数),其中ei序列唯一;
根据题意,求的就是n的约数个数
假设,n=p^x;在n的约数中,取p的有(x+1)种情况
设n%(a*b)中a = p^i,
则此时b可取p^0,p^1...p^(x-i), 共 (x-i+1) 个(a,b);
另i:0->x, 则共有sum(x)种合法答案!
如8:(下列冒号前表示a,冒号后表示b)
1:1,2,4,8
2:1,2,4
4:1,2
8:1
得出:f(p^k) = sum(k+1);
对于f(p*q);
如果令f(q)的分解a*b恒为1(即无视),则f(p*q)=f(q);
同理令f(p)的分解为1,f(p*q)=f(q);
根据乘法定理: f(p*q)=f(p)*f(q);
另外还有一种比较明显的思路:
要使得n%(a*b)==0就是令a*b为n的因子,
设a恒为1,则b可取数为n的因子个数;
再对b就行一次分解即可(这节比较重要);
还是可以用8做例子:
1:1 1*(1*1)
2:1,2 1*(2*1),1*(2*2)
4:1,2,2 1*(4*1),1*(2*2),1*(2*2)
8:1,2,4,8 1*(8*1),1*(2*4),1*(4*2),1*(1*8)
同样还是sum!
*/
B
题目描述
“回文”是指正读反读都能读通的句子,它是古今中外都有的一种修辞方式和文字游戏,如“我为人人,人人为我”等。在数学中也有这样一类数字有这样的特征,成为回文数
现在出题如下:
对于10进制数87:
STEP1:87+78 = 165 STEP2:165+561 = 726
STEP3:726+627 = 1353 STEP4:1353+3531 = 4884
上例用了4步得到回文数,在这里的一步是指进行了一次N进制的加法
写一个程序,给定一个N(2<=N<=10)进制数 , M(小于1000位数),求最少经过几步可以得到回文数。
如果在30步以内(包含30步)不可能得到回文数,则输出“Impossible!”
输入
N和M
输出
步数
样例输入
9
87
样例输出
STEP=6
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 30009
char a[maxn],b[maxn];
int n;
void rev(char*s){//反转s
int j = strlen(s)-1,i=0;
char t;
while(i<j){
t= s[i];
s[i++]=s[j];
s[j--]=t;
}
}
int check(char *a){//检查回文
strcpy(b,a);
rev(b);
return strcmp(a,b);
}
int add(){//n进制加法
strcpy(b,a);
rev(b);
int len = strlen(a),bit=0,t,i;
for(i=0;i<len;i++){
t = (a[i]-'0')+(b[i]-'0')+bit;
a[i]=t%n+'0';
bit = t/n;
}
if(bit)
a[i]=bit+'0';
return check(a);
}
int main(){
scanf("%d",&n);
scanf("%s",a);
rev(a);
int ans = 1;
if(check(a)==0){
ans = 0;
printf("STEP=0\n");
}
for(int i=1;ans&&i<=30;i++){
if(add()==0){
printf("STEP=%d\n",i);
ans = 0;
break;
}
}
if(ans)printf("Impossible!\n");
return 0;
}
/**
这是一道按照说明模拟就可以出答案的题;
*/
C
题目描述
话说,小C经过上次被小T实力坑了一把以后呀,他就决定发明一个数字游戏来坑一坑小T!游戏规则是这样~
在游戏开始前,小C会任意的选出一个正整数n(1≤n≤2^32-1),同时令m=1。在玩的过程当中,小C和小T每个人都可以将m的值扩大2到9中的任意倍数(倍数一定是整数),两个人一人扩大一次,第一个使m≥n的人就是最后的赢家。
因为两个人都在互相算计,所以都是用的最佳策略,问最后是谁赢?
(上次因为吃了先手的亏,小C决定先手,也就是说:每次都是小C第一个玩)。
输入
多组输入(文件尾结束)
每行一个正整数n
输出
对于每个结果:
如果小C赢,则输出"C",
如果小T赢,则输出"T"。
(记得换行!!)
样例输入
9
样例输出
C
#include <cstdio>
#include <cmath>
#define maxn 4294967295L
long long arr[100];
int p;
void init(){
int i;
for(i=1;;i++){
arr[i]=(long long)pow(18,i);
if(arr[i]>=4294967295L)break;
}
p=i;
}
int main(){
init();
long long n;
while(~scanf("%lld",&n)){
int i;
for(i=1;i<p;i++)
if(arr[i]>=n)break;
if(n>arr[i]/2)printf("T\n");
else printf("C\n");
}
return 0;
}
//4294967295
/**
博弈论!
对于这中不公平博弈,先手是很占优势的;这类题的通解思路:
如果先手可以到达终止局面,直接跳终止局面获得胜利
否则,把对手推到必败局面,相当于获得胜利!
再否则,开局投降无需挣扎....
思路很简单,关键在找必败局面:
把问题稍微转换一下,便于找必败局面: 把m每次乘以2-9直到大于等于n -> 把n每次除以2-9(向上取整)直到n<=1为获胜;
那么可以一次到达目标局的区间是[1-9]
第一个必败局面是(9,18],因为除9达不到1,除其他数对手必胜;
同理可以一次到达(9-18]的必败局(新目标局)的区间是(19,18*9]
再推一个必败局(18*9,18*9*2],再推一个必胜局[18*9*2+1,18*9*2*9]
再推一个必败局(18*9*2*9,18*9*2*9*2]
呵呵,找到规律了吗?
*/
D
题目描述
有小明和小曹两个无聊的人,对字符串操作起了兴趣,小曹给出一个由小写字母构成的字符串,小明给出另一个比小曹更长的字符串,也由小写字母组成,如果能通过魔法转换使小明的串和小曹的变成同一个,那么他们两个人都会很开心。这里魔法指的是小明的串可以任意删掉某个字符,或者把某些字符对照字符变化表变化。如:
小曹的串是 abba;
小明的串是 addba;
字符变化表 d b (表示d能转换成b)。
那么小明可以通过删掉第一个d,然后将第二个d转换成b将串变成abba。
现在请你帮忙判断:他们能不能通过魔法转换使两个人的串变成一样呢?
输入
首先输入T,表示总共有T组测试数据(T <= 40)。
接下来共T组数据,每组数据第一行输入小曹的字符串,第二行输入小明的字符串(数据保证字符串长度不超过1000,小明的串的长度大于等于小曹的,且所有字符均为小写字母)。接着输入字母表,先输入m,表示有m个字符变换方式(m< = 100),接着m行每行输入两个小写字母,表示前一个可以变为后一个(但并不代表后一个能变成前一个)。
输出
对于每组数据,先输出Case数。
如果可以通过魔法转换使两个人的串变成一样,输出“happy”,
否则输出“unhappy”。
每组数据占一行,具体输出格式参见样例。
样例输入
2
abba
addba
1
d b
a
dd
0
样例输出
Case #1: happy
Case #2: unhappy
#include <cstdio>
#include <cstring>
#define maxn 30
char a[1009],b[1009];
int g[30][30];
void init(){
for(int i=0;i<maxn;i++)g[i][i]=1;
for(int k=0;k<maxn;k++)
for(int i=0;i<maxn;i++)
for(int j=0;j<maxn;j++)
if(g[i][k]&&g[k][j])
g[i][j]=1;
}
int check(){
int i,j,la = strlen(a),lb=strlen(b);
int ai,bi;
for(i=0,j=0;i<la&&j<lb;j++){
ai = a[i]-'a';
bi = b[j]-'a';
if(g[bi][ai])
++i;
}
return i==la;
}
int main(){
int T,m;
char s[5],t[5];
scanf("%d",&T);
for(int cas=1;cas<=T;cas++){
scanf("%s%s%d",a,b,&m);
memset(g,0,sizeof(g));
for(int i=0,si,ti;i<m;i++){
scanf("%s%s",s,t);
si = s[0]-'a';
ti = t[0]-'a';
g[si][ti]=1;
}
init();
printf("Case #%d: ",cas);
if(check())printf("happy");
else printf("unhappy");
printf("\n");
}
return 0;
}
/**
题目意思开始不太明白,输入串a,b以及变换规则,如果b可以删除一些字符,在由变换规则转换一些字符可以变成a,则happy;
思路也很质朴:
把变换规则保存在图g中,通过floyd调整节点连通性(调整搜索也可)
遍历b,a;贪心匹配:
如果bi==ai,都跳下一个
否则如果bi到ai在图中连通,都跳下一个;
否则b跳下一个(相当于删一个字符)
最后,如果a遍历完了,就说明OK了;
*/
E
题目描述
上了大学的小明又在做题了,他好累,所以请你帮忙:
设n为正整数,令f(n)为所有gcd(x,y)的最大值,且x和y满足1<=x<y<=n,其中gcd指最大公约数。
举个例子:当n=3时,x,y可以取1,2或1,3或2,3,gcd(x,y)的最大值为1,因此f(3)=1。
给定正整数n,求当2<=i<=2*n+1时,所有f(i)的平方和。
输入
多组输入,最多100组
每组一个正整数 n < 10^9.
输出
仅一行,所求结果对10007取模的结果。
样例输入
3
样例输出
28
#include <cstdio>
#define MOD 10007
int main(){
int n;
long long ans;
while(~scanf("%d",&n)){
if(n%3==0){
ans = n/3;
ans = (ans%MOD*(n+1)%MOD*(2*n+1)%MOD)%MOD;
}else if((n+1)%3==0){
ans = (n+1)/3;
ans = (ans%MOD*(n)%MOD*(2*n+1)%MOD)%MOD;
}else{
ans = (2*n+1)/3;
ans = (ans%MOD*(n)%MOD*(n+1)%MOD)%MOD;
}
printf("%lld\n",ans);
}
return 0;
}
/**
有意思的是这个样例,如果样例ok就基本没问题了{ps:恰好卡了:( }
3
i数是:2,3,4,5,6,7
f(i) :1,1,2,2,3,3 (5为什么是2,7为什么是3呢?)
没错,就是这个规律: ans= (1^2+2^2...n^2)*2;
哈哈公式不记得吧?懵逼了?
1^2+2^2+..+n^2 = n(n+1)(2n+1)/6;
证明一下:
给定一个由数字组成的正三角形,第一行1个1,第二行2个2,第三行3个3,第N行n个n(这个三角所有和是什么?),按顺时针转60度,2次,每次得一个新三角形;
把这三个三角形对应位置数相加到结果三角形中,则结果三角中每个数都变成了 2n+1
结果三角中一共有多少数: 1+2+...n= n(n+1)/2
sum*3 = (2n+1)*n(n+1)/2
证毕!
最后须知 , 在 n, n+1 , 2n+1 这三个数中,始终有一个是3的倍数:
不妨设n非3的倍数,那么n%3可为1,2
为2: 则 n+1为3的倍数
为1: 则2n+1为3的倍数( (2n+1)%3== 2%3*n%3+1%3=6 )
*/
F
题目描述
拉丁方的定义 : n个不同的符号(这里取1到n),在n*n的方阵中每个符号在每一行和每一列均只出现一次,那么我们称此方阵为n阶的拉丁方
求最小n阶拉丁方,最小拉丁方中每行所表示的十进制数最小
输入
多组输入,每组一个n ( n <= 12 )
输出
输出最小拉丁方,每组输出数据之间用一个换行隔开
样例输入
1
2
样例输出
1
1 2
2 1
#include <cstdio>
#include <cstring>
int g[15][15],c[15][15],r[15][15],n,ok;
void cdfs(int i,int j){//按列搜
if(j==n||ok){
ok=1;
return ;
}
int x;
for(x=1;x<=n;x++)
if(!c[j][x]&&!r[i][x]&&!g[i][j]){
c[j][x]=r[i][x]=1;
g[i][j]=x;
cdfs(i,j+1);
if(ok)return ;
g[i][j]=0;
c[j][x]=r[i][x]=0;
}
if(i==n-j-1)cdfs(i,j+1);
}
void rdfs(int i){//按行搜
if(i==n){
for(int k=0;k<n;k++){
for(int j=0;j<n;j++)
printf((j==n-1)?"%d\n":"%d ",g[k][j]);
}
printf("\n");
return;
}
ok=0;
cdfs(i,1);
rdfs(i+1);
}
int main(){
while(~scanf("%d",&n)){
memset(g,0,sizeof(g));
memset(c,0,sizeof(c));
memset(r,0,sizeof(r));
for(int i=0;i<n;i++){
g[0][i]=g[i][0]=i+1;
g[i][n-i-1]=n;
r[i][n]=c[i][n]=1;
r[i][i+1]=c[i][i+1]=1;
}
rdfs(1);
}
return 0;
}
/**
没法理解题目,根据错误数据判断出来这么做是对的;(为什么不比赛的时候多提交几次套套答案呢?)
5
1 2 3 4 5
2 1 4 5 3
3 4 5 1 2
4 5 2 3 1
5 3 1 2 4
6
1 2 3 4 5 6
2 1 4 3 6 5
3 4 5 6 1 2
4 3 6 5 2 1
5 6 1 2 3 4
6 5 2 1 4 3
规律就是: 副对角线为n,1行与1列递增,其他位置从小到大,可行即填入;
写了一波垃圾剪枝
*/
G
题目描述
问题很简单,找出现了3*k-1次的数 ( k > 0 )
输入
输入一个 n 接下来就是n个数
确保有一个数出现了 3*k-1次,其余数都出现了3*m 次 (m > 0 )
对于所有的数在int范围内,且n小于216660
输出
找出现了3*k-1次 的那个数
样例输入
5
3 3 3 2 2
样例输出
2
#include <cstdio>
using namespace std;
#define maxn 32
int bit[maxn];
int main(){
int n,x,ans=0;
scanf("%d",&n);
while(n--){
scanf("%d",&x);
for(int i=0;x;i++){
bit[i]+=x%2;
x/=2;
bit[i]%=3;
}
}
for(int i=0;i<maxn;i++){
ans+=bit[i]*(1<<i);
}
printf("%d\n",ans/2);
return 0;
}
/**
异或和二进制永远都是神器
把所有输入数的二进制保存起来,
出现3k次的,其二进制的某位一定为3的倍数;(3k-1就是2的倍数嘛)
*/
H
题目描述
小C和小T骑车去郊游,小T先出发,速度为x米每分钟,行驶m分钟后,小C带着一条狗出发,小C的速度为y米每分钟,而狗则以每分钟z米的速度向小T跑去,追上小T后又会返回,如此往复,直到小C追上小T。问:当小C追上小T的时候,狗跑了多远?
输入
第一行输入一个整数N,表示测试数据的组数(N<100)
每组测试数据占一行,是四个正整数,分别为m,x,y,z(数据保证X<Y<Z)
输出
输出狗跑的路径长度,结果保留小数点后两位。
样例输入
1
5 10 15 20
样例输出
200.00
#include <cstdio>
int a[4];
int main(){
int T;
scanf("%d",&T);
while(T--){
for(int i=0;i<4;i++)
scanf("%d",a+i);
double ans = ((1.0*a[0]*a[1])/(a[2]-a[1])*a[3]);
printf("%.2lf\n",ans);
}
return 0;
}
/**
看完的第一反应是狗沿直线跑很远很远,超过了所有人!
*/
I
题目描述
小小成现在拥有n根火柴,假设小小成只能按照上图的方式用火柴摆数字,并且不能进行任何运算,而且必须
用完所有火柴棍,请问能摆出来的最大数字和次大数字是多少 。
输入
多组输入( 最多 2000 组 )
每组数据仅一行,包含一个正整数 n 。
1 ≤ n ≤2000
输出
对于每组数据输出一行,如果能摆出来的最大数字和次大数字都存在,则这一行包含两个非负整数,表示能摆出来的最大数字和次大数字
否则在这一行输出 small small cheng is silly boy
样例输入
5
1
样例输出
71 17
small small cheng is silly boy
#include <cstdio>
char ans[10009];
int ap;
void solve(int n){
int a=0,b=0;
if(n%2==0)
a=n/2;
else {
ans[ap++]='7';
a=(n-3)/2;
}
while(a--) ans[ap++]='1';
}
int main(){
int n;
while(~scanf("%d",&n)){
ap=0;
if(n<4)printf("small small cheng is silly boy\n");
else if(n==4)printf("11 4\n");
else{
solve(n);
ans[ap]=0;
if(ans[0]=='1'){
printf("%s ",ans);
ans[0]=ans[1]='7';
ans[ap-1]=0;
printf("%s\n",ans);
}else{
printf("%s ",ans);
ans[0]^=ans[1]^=ans[0]^=ans[1];
printf("%s\n",ans);
}
}
}
return 0;
}
/**
观察图:能拼出数字的需要火柴:2,3,4,5,6,7; 分别对应数字1,7,4,5,9,8
根据贪心的原则,肯定要多拼出几位数啊.因为4=2+2,5=2+3,6=3+3,7=2+2+3...
所以只有2,3有效,也就是说,拼出的数字只有1,7
有坑!
考虑5根以下火柴:
1:没用
2:只能拼出1,没有次大数
3:只能拼出7
4:只能拼出11?(呵呵,一个思维死角)
如果最大数7打头,7后移一位就是次大数
如果最大数全为1,把头三个1转换成77就是次大数
*/
J
题目描述
实验室除了是一个学习的地方,更是一个非常好玩的地方,有各种各样的活动充斥在学习之间。
在某一次活动中,黄sir带着大家一起去爬山。历经了千辛万苦后终于爬上了山顶,大家是又累又渴。。但是在山顶,只有一口井,每次只能容下一个人去打水。那么问题来了!
现在假设实验室有n个人,每个人打水的时间为ai,请给出一个排队的规则,使所有人的平均等待时间最小!
注意:若两个人的等待时间相同,则序号小的优先。
输入
多组输入
每组两行
第一行为n,表示有多少个人
第二行有n个数,分别表示每个人打水的时间a[1],a[2],a[3],a[4],……a[n],每个数据之间有一个空格
数据范围: 0<n<=1000, 0<a[i]<=1000
输出
对于每组输入
输出有两行(格式见样例)
第一行为使所有人的平均等待时间最小的排队顺序
第二行为最小的平均等待时间(输出结果精确到小数点后两位)
样例输入
10
56 12 1 99 1000 234 33 55 99 812
样例输出
3 2 7 8 1 4 9 6 10 5
291.90
提示
错误已更正~~
#include <cstdio>
#include <algorithm>
#define maxn 1009
struct A{
int id;
int val;
bool operator<(const A&x)const{
if(val!=x.val)
return val<x.val;
else return id<x.id;
}
}a[maxn];
int main(){
int n;
double sum=0;
while(~scanf("%d",&n)){
sum=0;
for(int i=0;i<n;i++){
scanf("%d",&a[i].val);
a[i].id=i+1;
}
std::sort(a,a+n);
if(a[n-1].val==a[n-2].val)
{//这是什么?
A t = a[n-2];
a[n-2]=a[n-1];
a[n-1]=t;
}
for(int i=0;i<n;i++){
if(i!=n-1)sum+=a[i].val*(n-i-1);
printf((i==n-1)?"%d\n":"%d ",a[i].id);
}
printf("%.2lf\n",sum/n);
}
return 0;
}
/**
莫名其妙就错了,然后莫名其妙过的;
*/
K
题目描述
最近发现了一些神奇的数字,就是各个位都不相同的四位数,如1234 , 把所有数字从大到小排序后得到的数,减去从小到大得到的数,一直如此减下去,竟然一定会得到6174,那么你能求出要多少次这样的操作才能得到6174吗?
例如,从1234出发,依次可以得到4321-1234=3087、8730-378=8352、8532-2358=6174。这样就回到了6174。操作步数为3,所以输出3。
输入
第一行输入n,代表有n组测试数据。
接下来n行每行都写一个各位数字互不相同的四位数
输出
经过多少次上面描述的操作才能出现6174。
样例输入
1
1234
样例输出
3
#include <cstdio>
#include <algorithm>
#include <cstring>
char a[10],b[10];
int solve(){
int cnt = 0,i,j,ai,bi;
while(strcmp("6174",a)){
std::sort(a,a+4);
strcpy(b,a);
i=0;j=strlen(b)-1;
while(i<j){
b[i]^=b[j]^=b[i]^=b[j];
++i;
--j;
}
sscanf(a,"%d",&ai);
sscanf(b,"%d",&bi);
sprintf(a,"%d",bi-ai);
++cnt;
}
return cnt;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%s",a);
int ans = solve();
printf("%d\n",ans);
}
return 0;
}
/**
算不上搜索的搜索,强行搜索
*/