传送门:点我c++
题目很棒,感谢出题验题的大佬们。数组
细节坑很多,是好事。ide
仍是很菜,继续加油!函数
B:学习
描述测试
桃子这几天在收集记念币,总共最多只有N种不一样的记念币,他已经收集了K种不一样的记念币。这不,桃子的生日快到了,他的M个小伙伴们决定送他记念币,如何送给桃子呢?他们都赞成了以下三个规则:
spa
1. 每一个人送的记念币与其余人的都同样多;code
2. 送给桃子的任意两枚记念币种类均不一样; blog
3. 桃子从小伙伴那获得至少L枚新的。递归
但他的小伙伴们不知道桃子收集了哪些记念币。他们想尽可能少花钱,因此他们想购买知足规则的最少数量的记念币。
输入
第一行一个整数T(≤100),表明有T组数据。
对于每组数据,包含一行为四个整数N, M, K, L(1≤K≤N≤1018,1≤M,L≤1018),表明有N种不一样的记念币,M个小伙伴,桃子原本有K种不一样的记念币,最后桃子手上至少有L枚新的记念币。
输出
输出桃子的一个小伙伴赠送的最少数量的记念币。若是不可能同时知足三个条件输出-1。
样例输入
2
20 15 2 3
10 11 2 4
样例输出
1
-1
提示
第一组数据:桃子的小伙伴每人送一枚记念币,由于桃子原来有2种记念币,小伙伴总共送15枚,必定有至少13枚是新的,知足题目要求且最少。
第二组数据:总共有10种不一样的记念币,而桃子的小伙伴有11个,不能知足条件2。
思路:
首先,提示告诉咱们若是M>N是直接输出-1。
很明显能够看出K+L是要达到的个数,若是K+L > M,也是能够直接输出-1的,由于达不到。
最后直接判断每一个人送知足条件的个数,会不会超过N便可。具体看代码有注释
代码:
#include<bits/stdc++.h> using namespace std; #define LL long long #define INF 2000000000 #define eps 1e-8 #define pi 3.141592653589793 const LL mod = 1e9+7; int main() { int _; for(scanf("%d",&_);_--;){ LL n,m,k,l; scanf("%I64d%I64d%I64d%I64d",&n,&m,&k,&l); if(m > n){ puts("-1");continue; } LL sum = k+l; if(sum > n){ puts("-1");continue; } LL ans = (sum%m == 0)?sum/m:sum/m+1;//每一个人要送的个数,保证能够知足K+L if(ans * m > n){//若是每一个人送的总数超过了N,根据蜂巢原理一定会重复。因此不行 puts("-1");continue; } else{ printf("%I64d\n",ans); } } } /* 2 100 6 2 98 */
C
描述
taozi喜欢数学,可是遇到数学题就头疼,zdragon为了让你们高兴高兴,给taozi出了道难题:
S=∑qi (1≤i≤n),因为答案可能会很大,答案对p取模。
输入
输入第一行为测试样例组数T(1≤T≤100)。
对于每组数据第一行包含三个正整数n,q,p(1≤n,q,p≤109)。
输出
对于每组数据,输出一个S对p取模的值。
样例输入
2
3 2 100
4 511 520
样例输出
14
184
提示
对于第一个样例,21+22+23=14,对100取模,答案为14。
思路:
S=∑qi (1≤i≤n),这玩意首先是个等比数列求和。而后取模,很容易想到套等比数列求和公式,逆元,取模。然而会出错。。由于可能在模数的意义下可能没有逆元。
其实是等比数列二分求和处理这玩意(最近写过同样的题目因此知道怎么作)
考虑S=∑qi (0≤i≤n),注意是有0.
就是1+q^1+q^2+....q^n
而后当n是偶数的时候:
把这个式子分红先后相等长度的两部分
(p^0+p^1+..p^(n/2))+ (p^(n/2+1)+p(n/2+2)+...+p^n)
把后半部分的p^(n/2+1)提取出来。
(p^0+p^1+..p^(n/2)) * (p^(n/2+1)+1)
右边快速幂,左边递归
奇数的话去掉p^n,一样的操做去左边递归右边快速幂。
代码:
#include<bits/stdc++.h> using namespace std; #define LL long long #define INF 2000000000 #define eps 1e-8 #define pi 3.141592653589793 long long q(LL a,LL n,LL mod) { LL ans = 1LL,temp = a%mod; while(n){ if(n&1){ ans=(ans*temp)%mod; } n>>=1; temp=(temp*temp)%mod; } return ans; } LL sum(LL p,LL n,LL mod) { if(p==0)return 0; if(n==0)return 1; return (n&1)?(((1+q(p,n/2+1,mod))%mod*sum(p,n/2,mod)%mod)%mod):(((1+q(p,n/2+1,mod))%mod*sum(p,n/2-1,mod)+q(p,n/2,mod)%mod)%mod); } int main() { /* LL a,b,p; while(~scanf("%lld %lld %lld",&a,&b,&p)){ LL sum = 0;for(int i = 1 ; i <= a ; i ++){ sum += q(b,i,p); sum%=p; } cout<<sum<<endl; } */ LL a,b,p; int _; for(scanf("%d",&_);_--;){ scanf("%lld %lld %lld",&a,&b,&p); LL ans = sum(b,a,p); printf("%lld\n",(ans+p-1)%p); } }/* 2 3 2 100 4 511 520 */
E:
描述
YuYu最近正在学习多位数的乘法,crq想考考她的学习状况,但又懒得出题,所以直接拿了一副扑克牌。扑克牌去掉了大小王和牌面值较大的牌,只留下A、二、三、四、五、六、七、8 、9,每种花色有9张牌,牌面值分别为1~9,现从中抽出n张牌,crq要求YuYu从n张牌中挑出若干张组成乘法公式a*b=c,其中a、b和c都可以由多张牌拼接而成(如1和2能拼成12,也能拼成21),但a和b最可能是2位的正整数(由于YuYu惧怕太大的数)。
如给定4 5 6 9四张牌,能够组成:
6*9=54
9*6=54
一个公式中同一张牌最多只能使用一次。
输入
多组数据,第一行为数据组数T(T<=100)。
每组数据第一行为正整数n(n<=36),第二行为n个正整数,表示从一副牌中抽取的牌面值,全部牌面值在1到9之间。
输出
对于每组数据,输出最多有多少种可能的公式。
样例输入
2
4
6 9 5 4
5
1 6 6 6 9
样例输出
2
4
思路:
注意C没限制是两位数便可
一眼感受是36^4*100的题,实际100*100两个循环判断就好了。
交了打表代码过了。。不是很懂。
实际我操做的是 一个两位数乘以一个两位数等于一个四位数,好比说什么01*02=0004前面补个0
代码:
#include<bits/stdc++.h> using namespace std; #define LL long long #define INF 2000000000 #define eps 1e-8 #define pi 3.141592653589793 string change(int a1,int a2,int a3,int a4,int a5,int a6,int a7,int a8){ string s = ""; s += (a2+'0'); s += (a1+'0'); s += '*'; s += (a4+'0'); s += (a3+'0'); s += '='; s += (a8+'0'); s += (a7+'0'); s += (a6+'0'); s += (a5+'0'); return s; } set<string>s; int main(){ int _; while(~scanf("%d",&_)){ while(_--){ s.clear(); int n,a[40], cnt[12]; memset(cnt,0,sizeof(cnt)); scanf("%d",&n); for(int i = 0 ; i < n ; i ++){ scanf("%d",a+i); cnt[a[i]]++; } int sum = 0; for(int i = 1 ; i < 100 ; i++){ for(int j = 1 ; j < 100 ; j++){ int temp = i; int num1 = temp%10; int num2 = temp/10%10; temp = j; int num3 = temp%10;//个位 int num4 = temp/10%10;//十位 temp = i*j; int num5 = temp%10;//个位 temp/=10; int num6 = temp%10;//十位 temp/=10; int num7 = temp%10;//百位 temp/=10; int num8 = temp%10;//千位 if(num1 == 0||num3 == 0||num5 == 0)continue; if(num8 != 0){ if(num7 == 0 || num6==0)continue; }else{ if(num7!=0){ if(num6==0)continue; } else{ if(num6!=0){ if(num5 == 0)continue; } } } //cout<<num8<<num7<<num6<<num5<<endl; if(num1 != 0) cnt[num1]--; if(num2 != 0) cnt[num2]--; if(num3 != 0) cnt[num3]--; if(num4 != 0) cnt[num4]--; if(num5 != 0) cnt[num5]--; if(num6 != 0) cnt[num6]--; if(num7 != 0) cnt[num7]--; if(num8 != 0) cnt[num8]--; if( cnt[num1] >= 0 && cnt[num2] >= 0 && cnt[num3] >= 0 && cnt[num4] >= 0 && cnt[num5] >= 0 && cnt[num6] >= 0 && cnt[num7] >= 0 && cnt[num8] >= 0 ){ string ss = change(num1,num2,num3,num4,num5,num6,num7,num8); s.insert(ss); } if(num1 != 0) cnt[num1]++; if(num2 != 0) cnt[num2]++; if(num3 != 0) cnt[num3]++; if(num4 != 0) cnt[num4]++; if(num5 != 0) cnt[num5]++; if(num6 != 0) cnt[num6]++; if(num7 != 0) cnt[num7]++; if(num8 != 0) cnt[num8]++; } } // for(set<string>::iterator it = s.begin() ; it != s.end();it++){ // cout<<*it<<endl; // } printf("%d\n",s.size()); }} } /* */
H:
描述
桃子很喜欢数学,最近他对lcm(最小公倍数)很是感兴趣。小翁看到桃子在纸上写了一大堆数学公式,就想考考桃子。他给小桃出了个题:如今你手上有一个数b,对于每一个1≤a≤1018,他把lcm(a,b)/a的不一样值写在了纸上,他想问你,他能在纸上写几个不一样的数字。
输入
第一行一个整数T(≤50),表明有T组数据。
对于每组数据,第一行一个整数b(1≤n≤1010),表明小桃手上的数b。
输出
输出一个数表明不一样值的个数。
样例输入
2
1
2
样例输出
1
2
提示
第一个样例,b等于1,只有1个值1。
第二个样例,b等于2,只有2个值1和2。
思路:
打个表(a 从1到b+10 )
就能发现当a > b时候题目那个式子答案都同样。而后出现的不同的值都是b的约数。因此题目转化成了求b的约数个数。
(首A拿到了,笑)
复杂度是O(sqrt(n))
代码:
#include<bits/stdc++.h> using namespace std; #define LL long long #define INF 2000000000 #define eps 1e-8 #define pi 3.141592653589793 int main() { int n; scanf("%d",&n); while(n--){ LL a;int sum = 0; scanf("%lld",&a); LL k = sqrt(a); for(int i = 1 ; i <= k; i++){ if(a%i==0){ sum+=2; } } if(k*k==a)sum--; printf("%d\n",sum); } return 0; }/* */
I:
描述
C++课上,老师讲到了映射map,桃子以为映射很神奇,能够把一个串变成一个数存储,也能够把一堆很大的数字变成很小的数字。为了加深对映射的印象,桃子出了下面这个题:
桃子将给你一个长的十进制数a,包含n个1-9的数字,你有一个映射函数f能够把x变成f(x)。
你能够执行如下操做不超过1次:选择一个非空的连续子段并把里面的每一个数字x映射成f(x)。例如a=1337,f(1)=1,f(3)=5,f(7)=3,你将选择区间[2,3],并把3变成f(3)=5,最终获得1557。
如今你执行了操做不超过1次,你能够获得的最大数是多少。
输入
第一行一个整数T(1≤T≤95),表明有T组数据。
对于每组数据:
第一行为一个整数n(1≤n≤2*105),为十进制数a的长度。
第二行为n个数字组成的整数a:a1a2...an(1≤ai≤9)。
第三行为9个数字f(1),f(2),...,f(9),表明映射函数f。
数据保证∑n<=106。
输出
每组数据输出一行,表明桃子能获得的最大值。
样例输入
3
4
1337
1 2 5 4 6 6 3 1 9
5
11111
9 8 7 6 5 4 3 2 1
2
33
1 1 1 1 1 1 1 1 1
样例输出
1557
99999
33
思路:
记第i个数是num[i];
从前日后遍历第一个f(num[i]) > num[i]的改掉是最优的。而后一个坑的点是,继续遍历下去的时候能够是f(num[pos]) == num[pos]
举个例子
5
32314
1 4 3 7 1 1 1 1 1
这个数的第四个1要修改为为1,可让第五位的4变成7。
代码:
#include<bits/stdc++.h> using namespace std; #define LL long long #define INF 2000000000 #define eps 1e-8 #define pi 3.141592653589793 char s[200011]; int main() { int _; for(scanf("%d",&_);_--;){ int n; scanf("%d %s",&n,s); int f[11]; for(int i = 1; i <= 9 ;i++){ scanf("%d",f+i); } for(int i = 0 ; i < n ; i++){ int a = s[i] - '0'; if(f[a] > a){ int pos = i; while(f[a] >= a && pos < n){ s[pos] = f[a]+'0'; pos++; a = s[pos] - '0'; } break; } } printf("%s\n",s); } }/* 3 4 1337 1 2 5 4 6 6 3 1 9 5 11111 9 8 7 6 5 4 3 2 1 5 32314 1 4 3 7 1 1 1 1 1 */
J:
描述
桃子喜欢收藏,尤为是对项链有着奇怪的要求:每颗珠子的颜色必须不一样。因为各类缘由,他找不到这种项链,因此他决定本身给项链涂色。
如今他手上有n种不一样颜色的涂料,项链(环形)上有n颗珠子,他想知道他有多少种不一样的涂法。若一条项链能经过绕中心旋转或翻转而变成另外一个项链,则认为是同一种涂法。
输入
输入第一行为测试样例组数T(1<=T<=10000)。
对于每组数据包含一个正整数n(1<=n<=106),表明不一样颜色的涂料种数或珠子数目。
输出
对于每组数据,输出一个整数表明有多少种不一样的涂法。结果对109+7取模。
样例输入
2
3
4
样例输出
1
3
思路:
打表以后发现是(n!)/2。猜了2发(n+1)*n/2。。。。老老实实打表吧。
n= 1,2时候须要另外判断。(我是存数组而后直接输出)
代码:
#include<bits/stdc++.h> using namespace std; #define LL long long #define INF 2000000000 #define eps 1e-8 #define pi 3.141592653589793 const LL mod = 1e9+7; LL a[1000011]; int main() { a[0] = a[1] = a[2] = 1; for(int i = 3 ; i <= 1000000 ; i++){ a[i] = (a[i-1] * i)%mod; } int _; for(scanf("%d",&_);_--;){ int n; scanf("%d",&n); cout<<a[n-1]<<endl; } } /* 4 3 4 5 6 */
L:
描述
最近桃子爱上了博彩,一天他买了一张彩票,上面印着带有n个数字的序列a1a2a3...an。
若是一张彩票是幸运的,当且仅当其知足以下所有条件:
1. 序列能被刚好分红不相交的至少2段;
2. 每一段区间[l,r]的和都是相同的。
请你帮助桃子判断他手上的彩票是否是幸运的。
例如123426是幸运的,它能够分为3段,12三、42和6,1+2+3=4+2=6。
不相交就是序列的每一个数字刚好属于一个段。
输入
第一行一个整数T(≤100),表明有T组数据。
对于每组数据,第一行一个整数n(2≤n≤100),表明彩票中数字序列的位数。
第二行为一个长度为n的数字序列a1a2a3...an(0≤ai≤9)。
输出
若是这张彩票是幸运的,输出YES,不然输出NO。
样例输入
2
5
73452
4
1248
样例输出
YES
NO
提示
第一个样例:能分红3段,七、34和52,7=3+4=5+2。
第二个样例:不能分出。
思路:
求个前缀和,暴力枚举每一个区间可能的和,由于a_i都是很小的!!以后看看看看能不能划分就好了。
坑点:若是全部的数都是0,也是能够的。被这个坑了。
代码:
#include<bits/stdc++.h> using namespace std; #define LL long long #define INF 2000000000 #define eps 1e-8 #define pi 3.141592653589793 int main() { int _; for(scanf("%d",&_);_--;){ int n; scanf("%d",&n); string s;cin>>s; int a[101],flag = 0; int sum[111]; memset(sum,0,sizeof(sum)); for(int i = 0 ; i < n ; i++){ a[i] = s[i] - '0'; if(i == 0)sum[i+1] = a[i]; else sum[i+1] = sum[i]+a[i]; } if(sum[n] == 0){ puts("YES");continue; } for(int i = 0; i < sum[n]; i ++){ int pos = 0; for(int j = 1 ; j <= n ; j++){ int nowsum = sum[j] - sum[pos]; if(nowsum == i){ pos = j; // printf("%d %d\n",i,pos); } } if(pos == n || sum[pos] == sum[n]){ flag = 1; break; } } flag ? puts("YES"):puts("NO"); } }/* 4 20 00101000021000200100 5 73452 4 1248 8 10101000 1~10 */