姗姗来迟;
异或那道题没想出来可惜了;
官方标程:标程
A:欧几里得
打标找规律,题解说的斐波那契;
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
struct node
{
ll a,b;
}bb[100];
int main()
{
int t;
cin >>t;
bb[1].a=2,bb[1].b=1;
for(int i=2;i<=80;i++)
{
bb[i].a=bb[i-1].a+bb[i-1].b;
bb[i].b=bb[i-1].a;
}
while(t--)
{
int n;
cin >>n;
if(n==0) cout <<1<<endl;
else cout <<bb[n].a+bb[n].b<<endl;
}
}
.
.
B: 括号序列
思路是把向左的括号都放到栈里面,然后遇到向右的括号,就把它与栈顶的括号相匹配,匹配失败则不符合题意;
(最后一定要判断栈是否为空,只有栈是空的,说明才符合题意)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
map<char,char> mp;
int main()
{
mp[')']='(';
mp['}']='{';
mp[']']='[';
string s;
cin >>s;
int len=s.size();
stack <char> ss;
int flag=1;
for(int i=0;i<len;i++)
{
if(s[i]=='('||s[i]=='['||s[i]=='{')
{
ss.push(s[i]);
}
else
{
if(ss.empty())
{
flag=0;
break;
}
else
{
if(ss.top()==mp[s[i]]) ss.pop();
else
{
flag=0;
break;
}
}
}
}
if(!ss.empty()) flag=0;
if(flag) cout <<"Yes"<<endl;
else cout <<"No"<<endl;
}
.
.
C: 子段乘积
先求前缀乘积,然后区间【l,r】的乘积为mul [ r ] / mul [ l ] ;需要用到逆元;
并且需要判断这个子段中是否有0,快速的判断方法为,用前缀和处理原始数据,如果输入的是0,就标记为1,不是0,标记为0;
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
ll a[2*100005];
int b[2*100005];
int cnt,n,k;
ll qk(ll a,ll b)
{
ll res=1;
while(b)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
int main()
{
cin >>n>>k;
a[0]=1;
for(int i=1;i<=n;i++)
{
cin >>a[i];
if(a[i]==0) b[i]=b[i-1]+1,a[i]=a[i-1];
else
{
a[i]=a[i]*a[i-1]%mod;
b[i]=b[i-1];
}
}
ll ans=0;
for(int i=k;i<=n;i++)
{
if(b[i]-b[i-k]) continue;
ans=max(ans,a[i]*qk(a[i-k],mod-2)%mod);
}
cout <<ans%mod<<endl;
}
.
.
D:子段异或
这个题非常有意思,异或零的话是:x ^ x = 0 ;所以求出前缀和,当出现两次前缀和一样时,说明中间一定有一段子串的异或为0;如果该前缀和出现三次,那么说明这一次到第一次中间有两端子串的异或值为0;那么这两串可以组成三个不同的串;以此类推。。。。。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
map<ll,int> mp;
ll a[2000005];
int main()
{
int n;
cin >>n;
mp[0]=1;
ll ans=0,res=0;
for(int i=0;i<n;i++)
{
ll a[i];
cin >>a[i];
res^=a[i];
ans+=mp[res];
mp[res]++;
}
cout <<ans<<endl;
}
.
.
.
E.最小表达式
该题把数列从小到大排序后,如果有x个加号,那么把数列里面的数依次分给这(x+1)个子数列;再把这(x+1)个数列组成的数,相加即可;(大数运算)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[5*100001];
vector<int> add(vector<int> &A, vector<int> &B)
{
if (A.size() < B.size()) return add(B, A);
vector<int> C;
int t = 0;
for (int i = 0; i < A.size(); i ++ )
{
t += A[i];
if (i < B.size()) t += B[i];
C.push_back(t % 10);
t /= 10;
}
if (t) C.push_back(t);
return C;
}
int main()
{
string s;
cin >>s;
int len=s.size();
int cnt=0,cot=0;
for(int i=0;i<len;i++)
{
if(s[i]=='+') cot++;
else a[cnt++]=s[i]-'0';
}
sort(a,a+cnt);
vector<int> v[cot+1];
for(int i=0;i<=cot;i++)
{
stack<int> q;
for(int j=i;j<cnt;j+=(cot+1))
q.push(a[j]);
while(!q.empty()) v[i].push_back(q.top()),q.pop();
}
// for(int i=0;i<=cot;i++)
// {
// for(int j=0;j<v[i].size();j++) cout <<v[i][j];
// cout <<endl;
// }
vector<int> ans;
for(int i=0;i<v[0].size();i++) ans.push_back(v[0][i]);
for(int i=1;i<=cot;i++) ans=add(ans,v[i]);
for(int i=ans.size()-1;i>=0;i--) cout <<ans[i];
}
.
.
.
F:树上博弈
只有牛牛的初始位置和牛妹的初始位置距离为偶数时,牛牛获胜。只需要分别求出深度为奇数的点和深度为偶数的点的数量即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int dp[1000005];
ll cnt[2];
int main() {
int n;
cin >>n;
dp[1] = 0;
cnt[0] = 1;
for(int i=2;i<=n;i++){
int p;
cin >>p;
dp[i] = dp[p]^1;
cnt[dp[i]]+=1;
}
cout<<cnt[0]*(cnt[0]-1)+cnt[1]*(cnt[1]-1)<<endl;
return 0;
}