题目链接:Codeforces Round #474 (Div. 1 + Div. 2)
A:直接枚举每种情况即可,判断有没有其他字母,判断每个字母当中有没有其他字母,判断一下顺序就好了。
AC代码:
#include<bits/stdc++.h>
using namespace std;
string str; map<char,int> mp,pos,pre; set<int> st;
int main(){
cin>>str; str=" "+str;
for(int i=1;i<str.size();i++){
mp[str[i]]++,pos[str[i]]=i,st.insert(str[i]);
if(!pre[str[i]]) pre[str[i]]=i;
}
if(!mp['a']||!mp['b']||!mp['c']) return puts("NO"),0;
if(st.size()>=4) return puts("NO"),0;
if(pos['a']>pos['b']||pos['a']>pos['c']||pos['b']>pos['c']) return puts("NO"),0;
if(mp['c']!=mp['b']&&mp['c']!=mp['a']) return puts("NO"),0;
if(pos['a']-pre['a']!=mp['a']-1) return puts("NO"),0;
if(pos['b']-pre['b']!=mp['b']-1) return puts("NO"),0;
if(pos['c']-pre['c']!=mp['c']-1) return puts("NO"),0;
puts("YES");
return 0;
}
B:其实我们可以知道对于a改变k1次,对b改变k2次,我们可以看做是对a改变k1+k2次,所以每次暴力找一个最大差值,贪心即可。
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e3+10;
int n,k1,k2,a[N],b[N],m,res;
signed main(){
cin>>n>>k1>>k2; m=k1+k2;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) cin>>b[i];
while(m--){
int mx=-1e9,id=1;
for(int i=1;i<=n;i++){
if(abs(a[i]-b[i])>mx) id=i,mx=abs(a[i]-b[i]);
}
if(a[id]>=b[id]) a[id]--; else a[id]++;
}
for(int i=1;i<=n;i++) res+=(a[i]-b[i])*(a[i]-b[i]);
cout<<res<<endl;
return 0;
}
C:我们每次用很大的相同的数字去尽量接近当前的x,(也就是用2的次幂),然后x再减去当前的构成方案数,一直循环直到x很小的时候就暴力填单个数字即可。
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define int long long
using namespace std;
int x,d,m,base=1e16; vector<int> res;
int qmi(int a,int b){
int res=1; while(b){if(b&1) res=res*a; a=a*a; b>>=1;} return res;
}
signed main(){
cin>>x>>d;
while(x>3000){
for(int i=1;;i++){
if(qmi(2,i+1)-1>x){m=i; break;}
} x-=qmi(2,m); x++;
for(int i=1;i<=m;i++) res.push_back(base);
base-=1e12;
}
while(x--){base-=1e11; res.push_back(base);}
cout<<res.size()<<endl;
for(int i=0;i<res.size();i++) cout<<res[i]<<' ';
return 0;
}
D:因为是一个完全二叉树,所以树高是log级别的。然后暴力判断每一层右移了多少次(把左移看做右移)。每次看当前数字的上一个数字应该是多少,计算一下即可。其实可以预处理 2的次幂,更快。
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int q,cnt[70];
inline int get(int x){
int res=0; while(x){x>>=1LL; res++;} return res;
}
int qmi(int a,int b){
int res=1; while(b){if(b&1LL) res=res*a; a=a*a; b>>=1LL;} return res;
}
signed main(){
cin>>q;
while(q--){
int op,x,y,k; scanf("%lld %lld",&op,&x); y=x; x=get(x);
if(op==1){
scanf("%lld",&k); if(k<0) k+=qmi(2,x-1);
cnt[x]=(cnt[x]+k)%qmi(2,x-1);
}
else if(op==2){
scanf("%lld",&k); if(k<0) k+=qmi(2,x-1);
for(int i=x;i<=64;i++,k<<=1LL) cnt[i]=(cnt[i]+k)%qmi(2,i-1);
}else{
while(y){
int h=get(y),num=qmi(2,h-1);
printf("%lld ",y);
y=y+cnt[h]; y>>=1LL;
if(num!=1) y=(y-cnt[h-1]+num/2)%(num/2)+(num/2);
}
puts("");
}
}
return 0;
}
F:我们有一种很明显的DP,我们按照输入的顺序,建立N颗权值线段树,比如 A->B权值为C的边,我们每次从线段树A当中找权值小于C的最大值,加上一就是这个节点可能更新的最大值。但是N颗权值线段树空间太大了,所以我们动态开点即可。
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e5+10;
int n,m,res;
int rt[N],lc[N*20],rc[N*20],mx[N*20],cnt;
void change(int &p,int l,int r,int x,int v){
if(!p) p=++cnt;
if(l==r){mx[p]=max(mx[p],v); return ;}
int mid=l+r>>1;
if(x<=mid) change(lc[p],l,mid,x,v);
else change(rc[p],mid+1,r,x,v);
mx[p]=max(mx[lc[p]],mx[rc[p]]);
}
int ask(int p,int l,int r,int ql,int qr){
if(!p||l>r) return 0;
if(l==ql&&r==qr) return mx[p];
int mid=l+r>>1;
if(qr<=mid) return ask(lc[p],l,mid,ql,qr);
else if(ql>mid) return ask(rc[p],mid+1,r,ql,qr);
else return max(ask(lc[p],l,mid,ql,mid),ask(rc[p],mid+1,r,mid+1,qr));
}
signed main(){
cin>>n>>m;
for(int i=1,a,b,c,mx;i<=m;i++){
scanf("%d %d %d",&a,&b,&c); mx=0;
mx=ask(rt[a],0,1e5,0,c-1); res=max(res,mx+1);
change(rt[b],0,1e5,c,mx+1);
}
cout<<res<<endl;
return 0;
}