Problem B: Amazing Number
Time Limit:3000/1000 MS (Java/Others) Memory Limit:163840/131072 KB (Java/Others)
Total Submissions:92 Accepted:19
Description
对于两个正整数N和M, 如果M的各个数位上的数字之和加上M之和恰好为N, 我们称M是N的Amazing NumberAmazing Number. 现在给你一个正整数NN, 请你求出它的最小的Amazing NumberAmazing Number.
Input
第一行一个整数 T, 表示有T组数据. 接下来T行, 每行一个整数NN.
Output
对于每组数据, 输出MM. 若无解, 输出一行 No solutionNo solution
Sample Input
3 216 121 2005
Sample Output
198 No solution 1979
提示:显然只有各个位置数字之和只有18*9那往前判断18*9个数即可,T了可能是忘开longlong变负数了。
#include<bits/stdc++.h>
using namespace std;
inline int check(long long now){
int ans=0;
while(now){
ans+=now%10;
now/=10;
}
return ans;
}
int main()
{
int t; long long n;
scanf("%d",&t);
while(t--){
scanf("%lld",&n);
int flag=0;long long maxx=n-18*9;
if(maxx<=1)maxx=1;
for(long long i=maxx;i<=n;i++){
if(check(i)+i==n){
printf("%lld\n",i);flag=1;
break;
}
}
if(!flag){
printf("No solution\n");
}
}
}
Problem C: Dirichlet卷积
Time Limit:3000/1000 MS (Java/Others) Memory Limit:163840/131072 KB (Java/Others)
Total Submissions:13 Accepted:3
Description
在 算术函数集 上,可以定义一种二元运算,使得取这种运算为乘法,取普通
函数加法为加法,使得 算术函数集 为一个交换环。其中一种这样的运算便是Dirichlet 卷积。
它和一般的卷积有不少相类之处。
对于算术函数 f,gf,g,定义其 Dirichlet 卷积
(f∗g)(n)=∑d|nf(d)∗g(nd)(f∗g)(n)=∑d|nf(d)∗g(nd)
其中,d|nd|n表示:正整数n被d整除
Dirichlet 卷积有很多美妙的性质:
1. 取 Dirichlet 卷积为运算,积性函数集是算术函数集的子群。
2. 交换律 f∗g=g∗ff∗g=g∗f
3. 结合律 (f∗g)∗h=f∗(g∗h)(f∗g)∗h=f∗(g∗h)
4. 分配律 (f∔g)∗h=f∗g+f∗h=h∗(f∔g)(f∔g)∗h=f∗g+f∗h=h∗(f∔g)
5. 存在单位函数ε,使得 f∗ε=ε∗ff∗ε=ε∗f。 ε(n)的值为 1 若n = 1,否则ε(n) = 0。
6. 对于任意算术函数 f,若f(1)不等于 0,都有唯一的 逆函数 f−1f−1 ,使得f∗f−1=εf∗f−1=ε。
Mobius函数 μ的 逆函数 为(一般意义上的) 1,即对于n ≠ 1,
∑d|nμ(d)×1=0∑d|nμ(d)×1=0
这是Mobius反转公式的原理。
这些性质使得 Dirichlet 卷积在数论中
有着特别重要的地位。
现在定义一种运算,为有序序列的 Dirichlet 卷积
K 次自乘,假设原序列为f,结果序列为g,则有:
g=f∗f∗⋯∗f K个f
现在给出有序序列ff,请你求gg。
Input
第一行包含两个正整数 N,KN,K 。
下面一行N个正整数,第i个数表示fifi 。
Output
共一行,第i个数表示gigi mod 1000000009
Sample Input
5 2 50 56 85 43 60
Sample Output
2500 5600 8500 7436 6000
HINT
1≤N≤10,0001≤N≤10,000
1≤K≤101≤K≤10
0≤fi≤100,0000≤fi≤100,000
解释:g[1]=f[1]*f[1],g[2]=f[1]*f[2]+f[2]*f[1],
g[3]=f[1]*f[3]+f[3]*f[1],
g[4]=f[1]*f[4]+f[2]*f[2]+f[4]*f[1],
g[5]=f[1]*f[5]+f[5]*f[1]
提示:看起来像是要用什么高深的卷积...但是可以发现k只有10 n也只有10000,就是放着给我们暴力的。直接像筛素数一样就可以了(不会的可以先看埃氏筛法(素数筛))只不过改成先使2的所有倍数加上相应的值。循环k遍即可。
代码:
#include<bits/stdc++.h>
using namespace std;
const long long mod=1000000009;
long long a[12][10220];
int main()
{
int n;int k;
scanf("%d%d",&n,&k);k--;
for(int i=1;i<=n;i++){
scanf("%lld",&a[0][i]);
}
for(int ki=1;ki<=k;ki++){
for(int i=1;i<=n;i++){
for(int j=1;j*i<=n;j++){
a[ki][j*i]+=a[ki-1][j]*a[0][i]%mod;
a[ki][j*i]%=mod;
}
}
}
for(int i=1;i<=n;i++){
printf("%lld",a[k][i]);
if(i!=n) printf(" ");
} printf("\n");
}
Problem D: 这是一道数学题
Time Limit:3000/1000 MS (Java/Others) Memory Limit:163840/131072 KB (Java/Others)
Total Submissions:21 Accepted:2
Description
已知一个递推式an=an-1*X+Y,现在你知道X,Y,a0,且Y能被X-1整除,问k为多少时有ak能被a0整除。
Input
第1行一个T(T=10),表示有T组测试数据。
第2至T+1行每行有3个数X,Y,a0(0<X<231,0<=Y<263,0<a0<231),如题目描述所示。
Output
输出包括T行,每行输出一个数k(k>0),如果有ak能被a0整除且此时的k最小;若对于任何k都不满足条件,那么输出"Impossible!"
题解:鉴于是原题就直接贴别人的题解了?数论我也没学过ORZ
Problem E: A.CM真好玩!我要充钱
Time Limit:3000/1000 MS (Java/Others) Memory Limit:163840/131072 KB (Java/Others)
Total Submissions:16 Accepted:7
Description
A.CM是著名游戏厂商——鹅厂出品的一款游戏。
这是一款极度烧脑的硬核游戏。在游戏中,玩家面对着
各种算法题目,只有不断AC,才能一路过关斩将。还能
实时对战,跟别人一决高低。
既然是鹅厂出品的游戏,那么能让你迅速变强的方法是——充值。
现在可以充值VIP会员,能有专属VIP题库,还有题后分析、专属皮肤等......
mgnfcnt充了VIP会员,在关卡中碰到了这样一道题:
给定两个 1~n 的排列 A和B。定义一种操作:每
次可以取出 A 的最后一个数,然后插入到 A 的
任意一个位置(任意两个数中间或者最前面)。
现在要把 A 转化为 B,问最少需要几次操作
“氪不改命”,即使充了VIP,mgnfcnt还是菜。对于这题,他
毫无头绪,只好请教你了。
Input
第一行为一个整数,n。
第二行为 1~n 的一个排列,表示 A。
第三行为 1~n 的一个排列,表示 B。
Output
一个整数即最少操作次数。
Sample Input
5 1 5 2 3 4 1 2 3 4 5
Sample Output
3
HINT
n≤200000
提示:把A数组每一个元素在B数组中的下标作为该元素value则题目变成至少要把最后的多少个元素插入前面才能使A数组元素value递增。那显然如果A数组中有一个元素value小于其后面的数就不能使整个数组递增,那就把最靠前的这样一个元素插入都前面即可。
代码:
#include<bits/stdc++.h>
using namespace std;
int pos[200200];int a[200200];
int main()
{
int n;
scanf("%d",&n);int tmp;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
for(int i=0;i<n;i++){
scanf("%d",&tmp);
pos[tmp]=i+1;
}
for(int i=1;i<n;i++){
if(pos[a[i]]<pos[a[i-1]]){
printf("%d\n",n-i);break;
}
if(i==n-1){
printf("0");
}
}
}
F没看懂题意....也没根据题解脑补出题意有时间再补把。
Problem G: 这也是一道数学题
Time Limit:3000/1000 MS (Java/Others) Memory Limit:163840/131072 KB (Java/Others)
Total Submissions:23 Accepted:3
Description
给你一个数X(X<1e10),问你X除以1,2,...,X得到的整数部分中所有奇数之和减去偶数之和的差值的绝对值为多少。
Input
第一行一个T(T<=10),代表有T组测试数据。
第2至T+1行每行一个X(0<x<1e12),如题目描述所示。
Output
输出T行,每行一个数,代表每组数据得到的差值的绝对值。
Sample Input
2 10 100
Sample Output
1 110
提示:前X除以前面根号n个数显然有根号n个不同的结果。逐个处理即可。而后面的数为根号n到1,那判断每种数出现多少次就行。复杂度就O(n^0.5)
代码:
#include<bits/stdc++.h>
using namespace std;
int ans[1000100]; long long n;long long sq;
int main()
{
int t;long long aans;
scanf("%d",&t);
while(t--)
{
aans=0;
scanf("%lld",&n);
long long ji=0;
long long ou=0;
sq=sqrt(n);
long long now;aans=0;
for(int i=1;i<=sq;i++){
if((n/i)%2==0){
aans+=n/i;
}
else{
aans-=n/i;
}
}
now=sq+1;
for(int i=sq;i>0;i--){
if(i%2==0){
aans+=(n/i-now+1)*i;
}
else{
aans-=(n/i-now+1)*i;
}
now=n/i+1;
}
if(aans<0){
printf("%lld\n",-aans);
}
else{
printf("%lld\n",aans);
}
}
}
Problem H: 这是一道水题
Time Limit:3000/1000 MS (Java/Others) Memory Limit:163840/131072 KB (Java/Others)
Total Submissions:13 Accepted:0
Description
如果给你两个空瓶A,B,它们的容量分别为a,b,要你用这两个瓶子倒出体积为c的水。你可以将一个瓶子装满,把一个瓶子里的水倒到另一个瓶子中,以及倒空一个瓶子。问你要怎么做才能在最后使得B瓶中有体积为C的水?
Input
第1行一个T(T<=10),有T组测试数据。
第2至第T+1行每行三个数a,b,c(0<a<b<1e5,0<c<b),数据保证有解且操作次数不超过1000次。
Output
对于每组测试数据,每次操作共6种操作方式:
fill A
pour A B
empty A
fill B
pour B A
empty B
分别为把A倒满,把A中水倒入B,把A倒空,装满B,把B中水倒入A中,倒空B,把一个瓶中的水倒入另一个时默认前一个瓶倒空或后一个瓶倒满时停止这次操作。
你的每次操作需要从其中选一种,具体形式看样例输出。
每组样例的最后一行输出"success",表示操作结束。不需要输出多余空行,每行结尾没有空格。
又是原题.....翻译好像有点问题而且没有spj,出题人没有交过题,题目没说明是否要输出最少步数,而且.......比如1 2 1这种显然先倒到A评或B瓶都是两次操作数......不知道怎么处理 写法看原题
Problem I: Walk up and down
Time Limit:4000/2000 MS (Java/Others) Memory Limit:163840/131072 KB (Java/Others)
Total Submissions:6 Accepted:4
Description
现在有一栋n层的建筑, 里面有一个十分奇怪的电梯. 电梯里面只有唯一一个按钮, 当电梯在第i层的时候按下按钮, 下一步它将相同概率随机下降到i-1层或者上升到i+1层(第1层只能上升到第2层, 第n层只能下降到第n-1层). 最开始电梯在第1层, 小明想知道当他按了m次按钮之后电梯停在第k(1<=k <= n)层的概率是多少?
Input
第一行一个整数 T, 表示有T组数据.
接下来T行, 每行三个整数n,m,k .
Output
对于每组数据, 输出一个实数p, 表示问题描述的概率, 保留10位小数.
Sample Input
3 5 1 1 5 1 2 5 2 3
Sample Output
0.0000000000 1.0000000000 0.5000000000
HINT
1<T<30, 1<n<50, 0<m<1e9, 1<=k<=n.
题解:出题人原先希望正解是快速幂递推.....但是很显然10位的精确度根本挺不到20W....所以直接每次暴力算各层概率算20W次 然后比那个大的稍微判断下就ok
代码:
#include<bits/stdc++.h>
using namespace std;
double ans[2][60];
int main()
{
int t;
scanf("%d",&t);
while(t--){
memset(ans,0,sizeof(ans));
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
int maxm=min(m,200000);
ans[0][1]=1;
int now=0;
for(int mi=0;mi<maxm;mi++){
for(int i=1;i<=n;i++){
ans[now^1][i]= ans[now][i-1]*0.5+ans[now][i+1]*0.5;
if(i==2) ans[now^1][i]+= ans[now][i-1]*0.5;
if(i==n-1) ans[now^1][i]+= ans[now][i+1]*0.5;
}
now^=1;
}
if(m>=200000){
if(m&1) now^=1;
}
printf("%.10lf\n",ans[now][k]);
}
}