Educational Codeforces Round 96 (Rated for Div. 2)
A—Number of Apartments
题意:输入一个数是否由3、5、7组成,如果是输出组合形式,不是的话输出-1
思路:做的时候把它想的很难,其实是一道非常简单的题目,暴力的三重循环都可以过,也可以通过寻找数组之间的规律来构造,如果n%3==0那么就全部是3,如果n%3==1那么就退两个3出来构成7,如果不够两个那么就-1,如果n%3==2那么就退一个出来构成5,如果不够就-1。

#include<cstdio> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<stack> #include<queue> #include<cstring> #include<string> #include<set> //#include<unordered_map> using namespace std; #define m_p make_pair #define fi first #define se second #define pb push_back #define sz(x) (int)(x).size() #define pi acos(-1) #define IO ios::sync_with_stdio(false);cin.tie(0) typedef long long ll; typedef pair<int,int> pii; typedef pair<ll,ll>pll; const int inf=0x3f3f3f3f; const ll INF=0x3f3f3f3f3f3f3f3f; const int eps=1e-9; inline int gcd(int a,int b){return b?gcd(b,a%b):a;} inline int lcm(int a,int b){return a*b/gcd(a,b);} // inline int read() // { // int x=0,f=1; // char ch=getchar(); // while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar();} // while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } // return x*f; // } inline char nc() {static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;} inline void read(int &sum) {char ch=nc();sum=0;while(!(ch>='0'&&ch<='9')) ch=nc();while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+(ch-48),ch=nc();} const int maxn=1e5+50; int main() { // ios::sync_with_stdio(false); // cin.tie(0),cout.tie(0); int t,n; cin>>t; while(t--) { cin>>n; if(n%3==0) { cout<<n/3<<" "<<0<<" "<<0<<endl; }else if(n%3==1) { int ans=n/3; if(ans<2) cout<<-1<<endl; else { ans-=2; cout<<ans<<" "<<0<<" "<<1<<endl; } }else { int ans=n/3; if(ans==0) cout<<-1<<endl; else { ans-=1; cout<<ans<<" "<<1<<" "<<0<<endl; } } } return 0; }
B—Barrels
题意:给你一个长度为n的数列,你可以操作将两个数合并,然后剩下一个0,共可以操作k步
思路:把最大的k个相加就是答案
C—Numbers on Whiteboard
题意:给你一个长度为n的数列(从1到n),你可以任意选择两个数来合并变成(a+b)/2(要四舍五入),一共可以操作n-1次,问最后的答案最小的是多少,每一步是怎么选择的
思路:就试过几个数据之后,就可以发现每次把最后面的两个数结合一定是最小的,而且答案为2

#include<cstdio> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<stack> #include<queue> #include<cstring> #include<string> #include<set> //#include<unordered_map> using namespace std; #define m_p make_pair #define fi first #define se second #define pb push_back #define sz(x) (int)(x).size() #define pi acos(-1) #define IO ios::sync_with_stdio(false);cin.tie(0) typedef long long ll; typedef pair<int,int> pii; typedef pair<ll,ll>pll; const int inf=0x3f3f3f3f; const ll INF=0x3f3f3f3f3f3f3f3f; const int eps=1e-9; inline int gcd(int a,int b){return b?gcd(b,a%b):a;} inline int lcm(int a,int b){return a*b/gcd(a,b);} // inline int read() // { // int x=0,f=1; // char ch=getchar(); // while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar();} // while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } // return x*f; // } inline char nc() {static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;} inline void read(int &sum) {char ch=nc();sum=0;while(!(ch>='0'&&ch<='9')) ch=nc();while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+(ch-48),ch=nc();} const int maxn=1e5+50; int t,n; int main() { // ios::sync_with_stdio(false); // cin.tie(0),cout.tie(0); cin>>t; while(t--) { cin>>n; cout<<2<<endl; int ans=n; for(int i=n-1;i>=1;--i) { //cout<<i-1<<" "<<i<<endl; cout<<i<<" "<<ans<<endl; ans=(i+ans+1)/2; } } return 0; }
D—String Deletion
题意:给你一个只含有0、1的字符串,你每次选择一个数,然后他会去除开头连续相同的字符
问这样的步骤最多能操作几次
思路:可以想到如果都是010101....这样子循环下去那么他是两个才算做1个,然后连续的长度等于2,你就可以完成一次完整的操作,如果长度超过了2,就可以把多的补到前边连续长度为1的地方,也就是你拿的时候可以拿后面的,他去掉开头的单个,也算一步完整的操作。就从后往前遍历一遍就可以了。

#include<cstdio> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<stack> #include<queue> #include<cstring> #include<string> #include<set> //#include<unordered_map> using namespace std; #define m_p make_pair #define fi first #define se second #define pb push_back #define sz(x) (int)(x).size() #define pi acos(-1) #define IO ios::sync_with_stdio(false);cin.tie(0) typedef long long ll; typedef pair<int,int> pii; typedef pair<ll,ll>pll; const int inf=0x3f3f3f3f; const ll INF=0x3f3f3f3f3f3f3f3f; const int eps=1e-9; inline int gcd(int a,int b){return b?gcd(b,a%b):a;} inline int lcm(int a,int b){return a*b/gcd(a,b);} // inline int read() // { // int x=0,f=1; // char ch=getchar(); // while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar();} // while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } // return x*f; // } inline char nc() {static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;} inline void read(int &sum) {char ch=nc();sum=0;while(!(ch>='0'&&ch<='9')) ch=nc();while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+(ch-48),ch=nc();} const int maxn=1e5+50; int t,n; string s; int main() { // ios::sync_with_stdio(false); // cin.tie(0),cout.tie(0); cin>>t; while(t--) { cin>>n; cin>>s; //int num1=0,num2=0; int cnt=0; int ans=0,len=0; for(int i=n-1;i>=0;) { if(s[i]=='1') { int num=0; while(s[i]=='1'&&i>=0) num++,--i; if(num>1) { cnt+=num-2; ans+=1; }else if(num==1) { if(cnt>0) cnt--,ans++; else len++; } }else { int num=0; while(s[i]=='0'&&i>=0) num++,--i; if(num>1) { cnt+=num-2; ans+=1; }else if(num==1) { if(cnt>0) cnt--,ans++; else len++; } } } //cout<<ans<<" "<<len<<endl; cout<<ans+(len+1)/2<<endl; } return 0; }
E—String Reversal
题意:给你一个字符串,你可以交换两个相邻位置的元素,直到交换到原字符串的反字符串,问最少的操作步骤
思路:用贪心的思想,将反字符串求出来,每次都将相应的源字符串中距离这个位置最近的字符交换到这个位置上。难点是怎么计算这个步长,可以用线段树或者树状数组来保存,用线段树的话,就把原来每个点都更新成1,然后取出这个点更新为0,步长就是在他之前的和

#include<cstdio> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<stack> #include<queue> #include<cstring> #include<string> #include<set> //#include<unordered_map> using namespace std; #define m_p make_pair #define fi first #define se second #define pb push_back #define sz(x) (int)(x).size() #define pi acos(-1) #define IO ios::sync_with_stdio(false);cin.tie(0) typedef long long ll; typedef pair<int,int> pii; typedef pair<ll,ll>pll; const int inf=0x3f3f3f3f; const ll INF=0x3f3f3f3f3f3f3f3f; const int eps=1e-9; inline int gcd(int a,int b){return b?gcd(b,a%b):a;} inline int lcm(int a,int b){return a*b/gcd(a,b);} // inline int read() // { // int x=0,f=1; // char ch=getchar(); // while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar();} // while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } // return x*f; // } inline char nc() {static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;} inline void read(int &sum) {char ch=nc();sum=0;while(!(ch>='0'&&ch<='9')) ch=nc();while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+(ch-48),ch=nc();} const int maxn=2e5+50; int n; char s[maxn],t[maxn]; int sum[maxn<<2]; void update(int rt,int l,int r,int pos,int x) { if(l==r) { sum[rt]=x; return; } int mid=(l+r)>>1; if(pos<=mid) update(rt<<1,l,mid,pos,x); else update(rt<<1|1,mid+1,r,pos,x); sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } int query(int rt,int l,int r,int L,int R) { if(L<=l&&r<=R) return sum[rt]; int mid=(l+r)>>1; int ans=0; if(L<=mid) ans+=query(rt<<1,l,mid,L,R); if(R>mid) ans+=query(rt<<1|1,mid+1,r,L,R); return ans; } set<int>st[30]; int main() { // ios::sync_with_stdio(false); // cin.tie(0),cout.tie(0); cin>>n; cin>>s+1; for(int i=1;i<=n;++i) t[i]=s[n-i+1]; for(int i=1;i<=n;++i) update(1,1,n,i,1); for(int i=1;i<=n;++i) { st[s[i]-'a'].insert(i); } ll ans=0; for(int i=1;i<=n;++i) { int need=t[i]-'a'; int pos=*st[need].begin(); update(1,1,n,pos,0); ans+=query(1,1,n,1,pos); st[need].erase(st[need].begin()); } cout<<ans<<endl; return 0; }