Educational Codeforces Round 178 div2(题解ABCDE)
A. Three Decks
#1.由于最后三个数会相等,提前算出来和,%3判断,再判前两个数是否大于
#include<iostream>
#include<vector>
#include<stdio.h>
#include<map>
#include<string>
#include<algorithm>
#include<queue>
#include<cstring>
#include<stack>
#include<array>
#include<cmath>
#include<set>
#include<unordered_set>
#include<unordered_map>
#include<iomanip>
using namespace std;
using ll = long long;
using llu = unsigned long long;
const ll inf = 0x3f3f3f3f3f3f3f3fll;
const ll MIN = -9187201950435737472ll;
ll mod = 1e9 + 7;
ll base = 131;
const int N = 1e4 + 10;
void solve()
{int a,b,c;cin>>a>>b>>c;if((a+b+c)%3==0){int tmp=(a+b+c)/3;if((a<=tmp)&&(b<=tmp))cout<<"YES"<<endl;else cout<<"NO"<<endl;}else cout<<"NO"<<endl;
}
int main()
{ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int t = 1;cin>>t;while (t--){solve();}return 0;
}
B. Move to the End
我们每次要从数组末尾拿1,2,3...一直到n 个数,对于每次取,我都可以拿一个数到数组末尾。
#1.为此我们可以取一个前缀max数组,讨论从后向前的k个元素的前缀max是否大于这个元素
#include<iostream>
#include<vector>
#include<stdio.h>
#include<map>
#include<string>
#include<algorithm>
#include<queue>
#include<cstring>
#include<stack>
#include<array>
#include<cmath>
#include<set>
#include<unordered_set>
#include<unordered_map>
#include<iomanip>
using namespace std;
using ll = long long;
using llu = unsigned long long;
const ll inf = 0x3f3f3f3f3f3f3f3fll;
const ll MIN = -9187201950435737472ll;
ll mod = 1e9 + 7;
ll base = 131;
const int N = 1e4 + 10;
void solve()
{int n;cin>>n;vector<ll>a(n+1);vector<ll>pre(n+1,0);for(int i=1;i<=n;i++){cin>>a[i];pre[i]=max(pre[i-1],a[i]);}ll sum=0;for(int i=n;i>=1;i--){sum+=a[i];if(pre[i-1]>a[i])cout<<sum-a[i]+pre[i-1]<<" ";else cout<<sum<<" ";}cout<<endl;
}
int main()
{ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int t = 1;cin>>t;while (t--){solve();}return 0;
}
C. Card Game
有n张卡,编号大的克制编号小的,特别的1克制n,每回合Alice先出,Bob后手,如Alice克制Bob则得Alice得这两张牌,反之Bob
#1.注意到由于Alice先手,只有无论Alice出任何牌Bob都能克制她时,Bob胜,其余情况Alice胜
#2.可以用vector存Alice的牌,set存Bob的牌,二分+特判
#include<iostream>
#include<vector>
#include<stdio.h>
#include<map>
#include<string>
#include<algorithm>
#include<queue>
#include<cstring>
#include<stack>
#include<array>
#include<cmath>
#include<set>
#include<unordered_set>
#include<unordered_map>
#include<iomanip>
using namespace std;
using ll = long long;
using llu = unsigned long long;
const ll inf = 0x3f3f3f3f3f3f3f3fll;
const ll MIN = -9187201950435737472ll;
ll mod = 1e9 + 7;
ll base = 131;
const int N = 1e4 + 10;
void solve()
{int n;cin>>n;string s;cin>>s;vector<int>a;s="#"+s;set<int>st;bool tag=true;for(int i=1;i<=n;i++){if(s[i]=='A')a.push_back(i);else st.insert(i);}int l=a.size();for(int i=0;i<l;i++){if(a[i]==n){if(!(st.count(1)))tag=false;}else{auto it=st.upper_bound(a[i]);if(a[i]==1){if(*it==n)tag=false;}else{if(*it<a[i])tag=false;}}}if(tag)cout<<"Bob"<<endl;else cout<<"Alice"<<endl;
}
int main()
{ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int t = 1;cin>>t;while (t--){solve();}return 0;
}
D. Array and GCD
给一个长为n的数组a,可以让数组中的任一元素减1,另一元素加1,也可只减不加,最后问最少删几个元素能让数组任意两个元素之间互质,(删元素要在操作之前),并且要保证操作后的数组中任意元素都是>=2的
#1. 要让任意两个元素之间互素,当数组中都是素数即可
#2.再来考虑操作,我能让数组中任意元素变化,但数组的总和只能是不变或变小的,假设剩了x个元素,它最小应该是前x个素数相加。
#3.到这只需用欧拉筛筛到1e7(大概6e5个素数),在对素数做前缀和,即为保留i个元素,i个元素的总和至少为多少
#4.保持贪心性质,删数只删最小的
#include<iostream>
#include<vector>
#include<stdio.h>
#include<map>
#include<string>
#include<algorithm>
#include<queue>
#include<cstring>
#include<stack>
#include<array>
#include<cmath>
#include<set>
#include<unordered_set>
#include<unordered_map>
#include<iomanip>
using namespace std;
using ll = long long;
using llu = unsigned long long;
const ll inf = 0x3f3f3f3f3f3f3f3fll;
const ll MIN = -9187201950435737472ll;
ll mod = 1e9 + 7;
ll base = 131;
const int N = 1e7 + 10;
const int M=1e6+4;
bool vis[N];
vector<int>primes;
ll pre[M];
void init(int x)
{vis[0]=vis[1]=true;for(int i=2;i<=x;i++){if(!vis[i])primes.push_back(i);int l=primes.size();for(int j=0;j<l&&primes[j]*i<=x;j++){vis[i*primes[j]]=true;if(i%primes[j]==0)break;}}
}
void solve()
{int n;cin>>n;vector<int>a(n+1);ll sum=0;for(int i=1;i<=n;i++)cin>>a[i],sum+=a[i];sort(a.begin()+1,a.end(),greater<int>());if(n<2){cout<<0<<endl;return;}for(int i=n;i>=2;i--){if(sum>=pre[i]){cout<<n-i<<endl;return;}sum-=a[i];}cout<<n-1<<endl;
}
int main()
{ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int t = 1;cin>>t;init(1e7);int l=primes.size();//cout<<l<<endl;for(int i=0;i<l;i++){pre[i+1]=pre[i]+primes[i];}while (t--){solve();}return 0;
}
E. Unpleasant Strings
给一个长为n的字符串s,其中只能出现26个字母前k个字母,q次询问,每次询问给一个字符串,对于每次询问给出至少添加几个字母能使它不为s的子序列。
#1.对于本就不是它的子序列的字符串,添加0个。那就需要判断以一个字符串是否为另一个字符串的子序列。k很小,可以将每种字符用vector存起来,在判断时,只需要遍历要判断的字符串,二分对于这个字符出现序列中第一个大于上一个位置的位置
#2.通过上述方法可以找到这个字符串作为子序列第一个末尾,对于后续元素至少要添加的元素数量,我们可以采用后缀和提前预处理出答案,后缀和是从后向前遍历,将k个元素都出现的一段视作1,再做后缀和
#include<iostream>
#include<vector>
#include<stdio.h>
#include<map>
#include<string>
#include<algorithm>
#include<queue>
#include<cstring>
#include<stack>
#include<array>
#include<cmath>
#include<set>
#include<unordered_set>
#include<unordered_map>
#include<iomanip>
using namespace std;
using ll = long long;
using llu = unsigned long long;
const ll inf = 0x3f3f3f3f3f3f3f3fll;
const ll MIN = -9187201950435737472ll;
ll mod = 1e9 + 7;
ll base = 131;
const int N = 1e4 + 10;
int main()
{ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int l,q,k;cin>>l>>k;string s;cin>>s;string str;vector<vector<int>>dp(k+1,vector<int>());vector<ll>suf(l+3,0);s="#"+s;for(int i=1;i<=l;i++){dp[s[i]-'a'+1].push_back(i);}suf[l]=0;int cnt=0;vector<bool>vis(k+1,false);for(int i=l-1;i>=0;i--){if(!vis[s[i+1]-'a'+1])cnt++,vis[s[i+1]-'a'+1]=true;suf[i]=suf[i+1]+(cnt==k);if(cnt==k){fill(vis.begin(),vis.end(),false);cnt=0;}}cin>>q;while(q--){cin>>str;int len=str.length();int pos=-1;bool tag=true;for(int i=0;i<len;i++){int x=str[i]-'a'+1;auto tmp=upper_bound(dp[x].begin(),dp[x].end(),pos);//cout<<tmp<<endl;if(tmp==dp[x].end()){tag=false;break;}pos=*tmp;//cout<<pos<<endl;}if(!tag){cout<<0<<endl;continue;}//cout<<pos<<endl;cout<<suf[pos]+1<<endl;}return 0;
}