传送门:点我
题目很棒,感谢出题验题的大佬们。
细节坑不少,是好事。
还是很菜,继续加油!
B:
桃子的生日
总提交: 344 测试通过: 43
描述
桃子这几天在收集纪念币,总共最多只有N种不同的纪念币,他已经收集了K种不同的纪念币。这不,桃子的生日快到了,他的M个小伙伴们决定送他纪念币,如何送给桃子呢?他们都同意了如下三个规则:
1. 每个人送的纪念币与其他人的都一样多;
2. 送给桃子的任意两枚纪念币种类均不同;
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
桃子的难题
总提交: 102 测试通过: 6
描述
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的扑克牌游戏
总提交: 14 测试通过: 3
描述
YuYu最近正在学习多位数的乘法,crq想考考她的学习情况,但又懒得出题,因此直接拿了一副扑克牌。扑克牌去掉了大小王和牌面值较大的牌,只留下A、2、3、4、5、6、7、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
总提交: 364 测试通过: 64
描述
桃子很喜欢数学,最近他对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:
桃子的长号
总提交: 347 测试通过: 47
描述
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:
桃子的项链
总提交: 102 测试通过: 17
描述
桃子喜欢收藏,尤其是对项链有着奇怪的要求:每颗珠子的颜色必须不同。由于各种原因,他找不到这种项链,所以他决定自己给项链涂色。
现在他手上有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:
桃子的幸运彩票
总提交: 172 测试通过: 23
描述
最近桃子爱上了博彩,一天他买了一张彩票,上面印着带有n个数字的序列a1a2a3...an。
如果一张彩票是幸运的,当且仅当其满足如下全部条件:
1. 序列能被恰好分成不相交的至少2段;
2. 每一段区间[l,r]的和都是相同的。
请你帮助桃子判断他手上的彩票是不是幸运的。
例如123426是幸运的,它可以分为3段,123、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段,7、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 */