传送门:2020牛客寒假算法基础集训营4
由于是个人总结向,所以有点精简,而且可能和官方的标程截然不同,当然如果有什么疑问可以留言或者私信交流。
A. 欧几里得
思路:
- 签到题吧,随便打表看n=0-5的情况,可以明显发现跟fib有关。
代码如下:
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define myits multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
using namespace std;
inline ll read(){
ll s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
void put1(){ puts("Yes") ;}
void put2(){ puts("No") ;}
void put3(){ puts("-1"); }
ll ans=0;
// ll gcd(ll a,ll b){ ans++;return b==0?a:gcd(b,a%b);}
using namespace std;
const int manx=2e6+5;
ll a[manx],b[manx];;
int main()
{
a[0]=1,a[1]=2,a[2]=3;
b[0]=0,b[1]=1,b[2]=2;
for(int i=3;i<=80;i++)
a[i]=a[i-1]+a[i-2],b[i]=b[i-1]+b[i-2];
ll p=read();
while(p--){
ll n=read();
cout<<a[n]+b[n]<<endl;
}
return 0;
}
B. 括号序列
思路:
- 签到题,左的入栈右的匹配,但浪费了我不少时间,注意最后判空。
代码如下:
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define myits multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
using namespace std;
inline ll read(){
ll s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
void put1(){ puts("Yes") ;}
void put2(){ puts("No") ;}
void put3(){ puts("-1"); }
ll ans=0;
ll gcd(ll a,ll b){ ans++;return b==0?a:gcd(b,a%b);}
using namespace std;
const int manx=2e6+5;
char a[manx];
int main()
{
string s;
cin>>s;
ll len=0;
for(int i=1;i<=s.size();i++){
char c=s[i-1];
if(c=='{'||c=='('||c=='[')
a[++len]=c;
else if(len==0){
put2();
return 0;
}
else if(c=='}'){
if(a[len]!='{'){
put2();
return 0;
}
else len--;
}
else if(c==')'){
if(a[len]!='('){
put2();
return 0;
}
else len--;
}
else if(c==']'){
if(a[len]!='['){
put2();
return 0;
}
else len--;
}
}
if(len==0) put1();
else put2();
return 0;
}
C. hanayo和米饭
思路:
- 签到题,线段树+暴力,线段树只用查询就可以了。
代码如下:
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
//#define ll long long
#define ll unsigned long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 998244353
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define myits multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
#define mid ((tree[k].l+tree[k].r)>>1)
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
#define kl k<<1
#define kr k<<1|1
using namespace std;
inline ll read(){
ll s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;
const int manx=2e5+10;
ll n,l,r,w,x,ans;
ll aa[manx];
struct node{
ll l,r,w,f;
}tree[4*manx];
inline void build(ll k, ll l, ll r)
{
tree[k].l=l,tree[k].r=r;
if(tree[k].l==tree[k].r){
tree[k].w=aa[l];
return ;
}
build(lson);
build(rson);
tree[k].w=(tree[kl].w*tree[kr].w)%mod;
}
inline void down(ll k)
{
tree[kl].f+=tree[k].f;
tree[kr].f+=tree[k].f;
tree[kl].w+=tree[k].f*(tree[kl].r-tree[kl].l+1);
tree[kr].w+=tree[k].f*(tree[kr].r-tree[kl].l+1);
tree[k].f=0;
}
inline void find2(ll k)
{
if(tree[k].l>=l&&tree[k].r<=r){
ans*=tree[k].w;
ans%=mod;
return ;
}
if(tree[k].f) down(k);
if(l<=mid) find2(kl);
if(r>mid) find2(kr);
}
int main()
{
ll n=read(),k=read();
for(int i=1;i<=n;i++)
aa[i]=read();
build(1,1,n);
ll myans=0;
for(int i=k;i<=n;i++){
ans=1;
l=i-k+1,r=i;
find2(1);
myans=max(ans%mod,myans);
myans%=mod;
// cout<<myans<<" "<<ans<<endl;
}
cout<<myans%mod<<endl;
return 0;
}
D. 子段异或
思路:
- 签到题,用一个map记录异或的路径,当走到重复点的时候,这个点对答案的贡献为 这个点在之前出现的次数。
代码如下:
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define myits multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
using namespace std;
inline ll read(){
ll s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
void put1(){ puts("Yes") ;}
void put2(){ puts("No") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;
const int manx=2e6+5;
ll a[manx],b[manx];
map<ll,ll>mp;
int main()
{
ll n=read();
for(int i=1;i<=n;i++){
a[i]=read();
}
ll ans=0;
ll x=0;
mp[0]=1;
for(int i=1;i<=n;i++){
x=x^a[i];
if(mp[x]) ans+=mp[x];
mp[x]++;
}
cout<<ans<<endl;
return 0;
}
E. 最小表达式
思路:
- 是我写的最久的一道,做的时候以为是dfs,做到一半才想起是贪心模拟题。
- 要使结果最小,肯定要把小的数字放前面,先把数字个数%(加号个数+1)的余数分配好,其余的暴力模拟就可以了。
代码如下:
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define myits multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
using namespace std;
inline ll read(){
ll s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
void put1(){ puts("Yes") ;}
void put2(){ puts("No") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;
const int manx = 5e5 + 5;
string add(string a,string b)
{
string c;
string d="0";
long int kmin,kmax,i;
reverse(all(a));
reverse(all(b));
if(a.length()>b.length()) {kmin=b.length();kmax=a.length();c=a;}
else {kmin=a.length();kmax=b.length();c=b;}
c.insert(c.length(),d);
for(i=0;i<kmin;i++)
{
if(a.at(i)>=48&&a.at(i)<=57) a.at(i)-=48;
if(a.at(i)>=97&&a.at(i)<=122) a.at(i)-=87;
if(b.at(i)>=48&&b.at(i)<=57) b.at(i)-=48;
if(b.at(i)>=97&&b.at(i)<=122) b.at(i)-=87;
c.at(i)=a.at(i)+b.at(i);
}
for(i=kmin;i<kmax+1;i++)
{
if(c.at(i)>=48&&c.at(i)<=57) c.at(i)-=48;
if(c.at(i)>=97&&c.at(i)<=122) c.at(i)-=87;
}
for(i=0;i<kmax;i++)
{
if(c.at(i)>=10)
{
c.at(i+1)+=c.at(i)/10;
c.at(i)=c.at(i)%10;
}
}
if(c.at(kmax)==0)
{
c.erase(kmax,kmax+1);
}
for(i=0;i<c.length();i++)
{
if(c.at(i)>=10) c.at(i)+=87;
if(c.at(i)<10) c.at(i)+=48;
}
reverse(all(c));
return c;
}
int main()
{
string s;
cin>>s;
sort(all(s));
cout<<s<<endl;
ll cnt=0;
for(int i=0;i<s.size();i++)
if(s[i]=='+') cnt++;
else break;
if(cnt==0) cout<<s<<endl;
else{
s=s.substr(cnt);
cnt++;
int k=s.size()%(cnt);
string a[cnt];
int index=0;
for(int i=0;i<k;i++){
a[index]+=s[i];
index++;
index%=(cnt);
}
index=0;
s=s.substr(k);
// cout<<s<<endl;
for(int i=0;i<s.size();i++){
a[index]+=s[i];
index++;
index%=cnt;
}
string ans="0";
for(int i=0;i<cnt;i++){
// cout<<a[i]<<endl;
// reverse(all(a[i]));
// reverse(all(ans));
ans=add(a[i],ans);
}
cout<<ans<<endl;
}
return 0;
}
F. 树上博弈
思路:
- 当先手与后手距离为偶数必胜,所以这题可以转化为求树上偶数长度的路径数。
- dp[i][0]表示子树到i结点的偶数路径数,1则为偶。
- 那么ans=dp[父][0]*dp[子][1]+dp[父][1]*dp[子][0]。
- 注意最后ans*2,因为位置可以互换。
代码如下:
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define myits multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
using namespace std;
inline ll read(){
ll s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
void put1(){ puts("Yes") ;}
void put2(){ puts("No") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;
const int maxn = 2e6+ 5;
ll dp[maxn][2], ans = 0;;
vector<int> vt[maxn];
void dfs(int u, int f)
{
dp[u][0]=1;
dp[u][1]=0;
for(int i =0;i<vt[u].size();i++){
int to=vt[u][i];
if(to==f) continue;
dfs(to,u);
ans+=dp[u][0]*dp[to][1];
ans+=dp[u][1]*dp[to][0];
dp[u][0]+=dp[to][1];
dp[u][1]+=dp[to][0];
}
}
int main()
{
ll n=read(),x;
for(int i = 1; i < n; i++){
x=read();
vt[x].push_back(i+1);
vt[i+1].push_back(x);
}
ans=0;
dfs(1,-1);
ans=ans<<1;
cout<<ans<<endl;
return 0;
}
G. 音乐鉴赏
思路:
- 直接化整为零,把n个人当成1个人,求出平均的平时成绩。
- 而90的期末成绩要前10%,就可以=90*0.9=81。
- 设期末成绩占比为x,可得方程:
- 81x+ans(1-x)=90 , 解得x 。
代码如下:
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define myits multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
using namespace std;
inline ll read(){
ll s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
void put1(){ puts("Yes") ;}
void put2(){ puts("No") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;
const int manx=1e6+5;
ll a[manx];
double ans=0;
int main()
{
ll n=read();
for(int i=0;i<n;i++){
a[i]=read();
ans=ans+a[i];
}
ans=ans*1.0/n;
printf("%.2lf",(90-ans)*1.0/(81-ans)*100);
cout<<"%";
return 0;
}
H. 坐火车
思路:
- 用树状数组维护颜色的前缀和,再用两个数组,一个维护前缀颜色,一个维护后缀颜色,每次计算的时候要减去当前颜色的后缀suf[col[i]]–,然后计算完要加上当前颜色的前缀pre[col[i]]++。
代码如下:
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define myits multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
#define lowbit(x) (x&(-x))
using namespace std;
inline ll read(){
ll s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
void put1(){ puts("Yes") ;}
void put2(){ puts("No") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;
const int manx=5e5+10;
ll col[manx],l[manx],r[manx];
ll pre[manx],suf[manx],ans[manx];
ll n;
void add(ll x,ll val){
while(x<=n){
ans[x]+=val;
x+=lowbit(x);
}
}
ll query(ll x){
ll res=0;
while(x){
res+=ans[x];
x-=lowbit(x);
}
return res;
}
int main()
{
n=read();
for(int i=1;i<=n;i++)
col[i]=read(),l[i]=read(),r[i]=read(),suf[col[i]]++;
for(int i=1;i<=n;i++){
suf[col[i]]--;
add(col[i],-pre[col[i]]);
cout<<query(r[i])-query(l[i]-1)<<" ";
pre[col[i]]++;
add(col[i],suf[col[i]]);
}
return 0;
}
I. 匹配星星
思路:
- 先对x排序,这样保证操作的时候x永远大于候选集合的x,然后看z,视情况操作,如果为0则放进候选的集合,如果是1就在候选集合里面选择小于自己且在集合里面y最大的那个元素,保证最优。
代码如下:
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define mysets multiset<ll>
#define myits multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
#define lowbit(x) (x&(-x))
using namespace std;
inline ll read(){
ll s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
void put1(){ puts("Yes") ;}
void put2(){ puts("No") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;
const int manx=1e5+10;
mysets s;
struct node{
ll x,y,z;
}a[manx];
bool cmp(node a, node b){
if(a.x==b.x) return a.z>b.z;
else return a.x<b.x;
}
int main()
{
ll n=read();
for(int i=1;i<=n;i++)
a[i].x=read(),a[i].y=read(),a[i].z=read();
sort(a+1,a+1+n,cmp);
ll ans=0;
myits it;
for(int i=1;i<=n;i++){
if(a[i].z){
it=s.lower_bound(a[i].y);
if(it!=s.begin()){
--it;
ans++;
s.erase(it);
}
}
else s.insert(a[i].y);
}
cout<<ans<<endl;
return 0;
}