题目描述
欧几里得算法是一种求最大公约数的有效算法,在算法竞赛中很常用。
这个算法的 Python 实现如下:
def gcd(a,b):
if b == 0:
return a
return gcd(b,a%b)现在,如果已知 gcd(a,b) 共递归了 n次,求所有可能的a,b中满足a>b>=0且a+b最小的一组的a与b之和。
输入描述:
第一行一个整数,T。
接下来T行一行一个整数,n。
输出描述:
T行,每行一个整数,代表a+b。
示例1
输入
复制1 0
1
0输出
复制1
1说明
gcd(1,0) 由于 b=0,不会递归,即是递归0次。示例2
输入
复制1 1
1
1输出
复制3
3说明
gcd(2,1)会递归一次至gcd(1,0)。备注:
1≤T≤81 0≤n≤800≤n≤80
思路列出几个数就可以发现规律,类似于斐波那契博弈的递推
#include<bits/stdc++.h>
using namespace std;
#define int long long
int ans=INT_MAX;
pair<int,int>a[100];
signed main(){
int t,n;
cin>>t;
while(t--){
cin>>n;
a[0].first=1,a[0].second=0;
a[1].first=2,a[1].second=1;
for(int i=2;i<=100;i++){
a[i].first=a[i-1].first+a[i-1].second;
a[i].second=a[i-1].first;
}
cout<<a[n].first+a[n].second<<endl;
}
//gcd(a,b);
} 题目描述
注意:数据已加强并进行了rejudge
给出一个仅包含'[',']','(',')','{','}'六种字符的括号序列,判断其是否合法。
输入描述:
一行一个字符串S,只包含题目中的六种括号字符输出描述:
输出为一行"Yes" 或"No"示例1
输入
复制(){}[]
(){}[]输出
复制Yes
Yes示例2
输入
复制({[]})
({[]})输出
复制Yes
Yes示例3
输入
复制([)]
([)]输出
复制No
No备注:
1≤∣S∣≤1000000利用栈,遇到左括号就给压进去,遇到有括号就开始进行匹配
#include<bits/stdc++.h>
using namespace std;
string s;
stack<char>stk;
bool f(){
for(char c:s){
if(c=='('||c=='{'||c=='['){
stk.push(c);
}
else{
if(stk.empty()){
return false;
}
else{
char top=stk.top();
if((c==')'&&top=='(')||
(c=='}'&&top=='{')||
(c==']'&&top=='[')){
stk.pop();
}
else{
return false;
}
}
}
}
return stk.empty();
}
int main(){
getline(cin, s);
if(f()){
cout<<"Yes";
}
else{
cout<<"No";
}
}题目描述
给出一个长度为 n 的数列 a1,a2,…,ana_1,a_2,\ldots,a_na1,a2,…,an,求其长度为 k 的连续子段的乘积对 998244353 取模余数的最大值。
输入描述:
第一行两个整数n,k。
第二行n个整数,a1,a2,…,ana_1,a_2,\ldots,a_na1,a2,…,an。输出描述:
输出一个整数,代表最大余数。示例1
输入
复制5 3 1 2 3 0 8
5 3
1 2 3 0 8输出
复制6
6说明
1∗2∗3mod 998244353=61*2*3\mod 998244353=61∗2∗3mod998244353=6备注:
1≤k≤n≤2∗105
0≤ai<9982443530 \le a_i <9982443530≤ai<998244353
思路
利用逆元,除法同余原理,滑动窗口,进行操作
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
int a[200030];
int power(int b,int n) {
int ans=1;
while(n>0) {
if((n&1)==1) {
ans=(ans*b)%mod;
}
b=(b*b)%mod;
n>>=1;
}
return ans;
}
signed main() {
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++) {
cin>>a[i];
}
if(k==0){
cout<<1<<endl;
return 0;
}
int ans=1;
int zero_count=0;
for(int i=1;i<=k;i++) {
if(a[i]==0)zero_count++;
else ans=(ans*a[i])%mod;
}
int res=(zero_count==0)?ans:0;
for(int i=k+1;i<=n;i++){
if(a[i-k]==0) zero_count--;
else{
ans=(ans*power(a[i-k],mod-2))%mod;
}
if(a[i]==0) zero_count++;
else ans=(ans*a[i])%mod;
if(zero_count==0){
res=max(res,ans);
}else{
res=max(res,0LL);
}
}
cout <<res%mod<<endl;
return 0;
}题目描述
输入一个数列a,你需要输出其中异或值为0的不同子段的数量。一个子段 [l,r] (1≤l≤r≤n1 \le l \le r \le n1≤l≤r≤n)的异或值为al⊕al+1⊕al+2⊕…⊕ara_l \oplus a_{l+1} \oplus a_{l+2} \oplus \ldots\oplus a_ral⊕al+1⊕al+2⊕…⊕ar,其中⊕\oplus⊕符号代表异或运算。
两个子段被视为相同的,当且仅当其开始和结束位置均对应相同。
输入描述:
第一行一个整数 n ,代表数列长度。
第二行 n 个整数,代表数列。
输出描述:
输出一个整数,代表答案。示例1
输入
复制5 1 2 3 2 1
5
1 2 3 2 1输出
复制2
2说明
子段 [1,3] 和子段 [3,5] 是合法子段。备注:
n≤200000,0≤ai≤2^30−1思路 找到prefix[l-1] 与prefix[r]相等,这俩异或肯定为0,然后prefix[r]一定也包括prefix[l-1]所以就可以知道l到r一定异或值为0
#include<bits/stdc++.h>
using namespace std;
long long prefix;
int a[200020];
int main(){
int n;
cin>>n;
unordered_map<long long ,long long>mp;
mp[0]=1;
for(int i=1;i<=n;i++){
cin>>a[i];
prefix^=a[i];
mp[prefix]++;
}
long long ans=0;
for(auto &p : mp){
long long c=p.second;
ans+=c*(c-1)/2;
}
cout<<ans;
}题目描述
给出一个包含数字1-9和加号的字符串,请你将字符串中的字符任意排列,但每种字符数目不变,使得结果是一个合法的表达式,而且表达式的值最小。输出那个最小表达式的值
合法的表达式的定义如下:
- 一个数字,如233,是一个合法的表达式
- A + B是合法的表达式,当且仅当 A , B 都是合法的表达式
保证给出的表达式经过重排,存在一个合法的解。
输入描述:
一行输入一个字符串,仅包含数字1-9和加号+。
字符串的长度小于5∗1055*10^55∗105。
输出描述:
一行输出一个数字,代表最小的解。示例1
输入
复制111+1
111+1输出
复制22
22说明
11+11=22示例2
输入
复制9998765432111
9998765432111输出
复制1112345678999
1112345678999示例3
输入
复制12+35
12+35输出
复制38
38说明
25+13 = 38
示例4
输入
复制23984692+238752+2+34+
23984692+238752+2+34+输出
复制5461
5461说明
嗯,这个答案是可以得到的
备注:
注意,答案长度可能长达500000个字符。思路
就是利用贪心加高精度,其实就是看一下+有几个然后分成几组数,然后把最小的数字都扔给最高位,再利用高精度相加
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 500010;
int res[MAXN];
int main() {
string s;
cin>>s;
vector<char>digits;
int k=0;
for(char c:s) {
if(c=='+'){
k++;
}
else{
digits.push_back(c);
}
}
sort(digits.begin(),digits.end());
int n=digits.size();
int m=k+1;
int len=n/m;
int r=n%m;
int start=0;
if(r>0){//有r组数需要多一位数
int S1=0;
for(int i=0;i<r;i++){
S1+=digits[start++]-'0';
}
res[len]+=S1;//所以从len开始
}
for(int j=len-1;j>=0;j--){
int S=0;
for(int i=0;i<m;i++) {//先把最小的数给最高位,所以从len-1开始
S+=digits[start++]-'0';
}
res[j]+=S;
}
int L=len+10;//防止进位时候越界
for (int i=0;i<L-1;i++) {
if(res[i]>=10){
res[i+1]+=res[i]/10;
res[i]%=10;
}
}
int high=L-1;
while(high>0&&res[high]==0){
high--;
}
for(int i=high;i>=0;i--){
cout<<res[i];
}
cout<<endl;
return 0;
}