除了AGL,要看这三题请移步。
D.简单的素数
很简单,但不能用素数筛,1e8量级跑一秒直接超时,直接暴力最简单的那种素数check就行
F.小磊的算式
也是签到,把加号之间的数字取出来就行了
#include <bits/stdc++.h>
using namespace std;
using ll =long long;
using pii = pair<int,int>;
using tri = tuple<int,int,int>;
void solve(){
string a;
cin>>a;
vector<int> pos;
vector<ll> nums;
for(int i = 0;i<a.size();i++) if(a[i]=='+') pos.push_back(i);
ll res = 0;
ll mid = 10;
for(int i = 0;;i++){
if(a[i]=='+'){
// cout<<res<<endl;
nums.push_back(res);
break;
}
res = res*mid+(a[i]-'0');
}
int lenpos = pos.size();
for(int i = 0;i<=lenpos-2;i++){
res = 0;
mid = 10;
for(int j = pos[i]+1;j<=pos[i+1]-1;j++){
res = res*mid+(a[j]-'0');
}
nums.push_back(res);
}
res = 0;
mid = 10;
for(int i = pos[lenpos-1]+1;i<a.size();i++){
res = res*mid+(a[i]-'0');
// mid = mid*10;
}
// cout<<res<<endl;
nums.push_back(res);
ll ans = 0;
for(auto x : nums) ans+=x;
sort(nums.begin(),nums.end());
reverse(nums.begin(),nums.end());
for(int i = 0;i<nums.size();i++){
if(i==nums.size()-1) cout<<nums[i];
else cout<<nums[i]<<'+';
}
cout<<endl<<ans<<endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int Text_number = 1;
// cin>>Text_number;
while(Text_number--) solve();
return 0;
}
H.聪明且狡猾的恶魔
思维题,已知只要有百分之五十以上的选票就能通过,所以只要保证半数人有钱可拿就行,还要保证拿到钱的人得到的钱相同,那就赋值为一,所以这题就解出来了,赛时说失误有0的样例,但我还是直接过了,输入为0输出的是x+1
void solve(){
int x,n;
cin>>x>>n;
int ans = 0;
if(n==1||n==2){
cout<<x<<endl;
return ;
}
if(n%2==0){
ans = x-n/2;
ans++;
}else{
ans = x-n/2;
}
cout<<ans<<endl;
}
B.小雷的神奇电脑
首先说同或运算,手搓发现只要让m位为1的数字减去要做同或运算的两个数字的异或值就能得到同或,紧接着,对数组进行sort,可以证明只有相邻的两个数才可能出现同伙最大值,因为相邻的两个数拥有相同的二进制前缀的概率更大;
void solve(){
vector<ll> a;
int n,m;
cin>>n>>m;
a.resize(n+1);
for(int i = 1;i<=n;i++) cin>>a[i];
sort(a.begin(),a.end());
int len = a.size();
ll ans = 0;
ll res = 0;
for(int i = 0;i<=m-1;i++) res = res+(1<<i);
for(int i = 1;i<len-1;i++){
ans = max(ans,res-(a[i]^a[i+1]));
}
cout<<ans<<endl;
}
C.岗位分配
赛时看到队友前三道签到都没写完直接把这题过了,可是本菜鸡还不会,赛后说是板子题,是插板法板子题,不会的可以移步至b站董晓算法插板法,看完就会了
const int mod = 998244353;
int a[1001];
int c[3001][3001];
int n,m;
void solve(){
cin>>n>>m;
ll sum = 0;
for(int i = 1;i<=n;i++) cin>>a[i],sum+=a[i];
for(int i = 0;i<=m+n;i++){
c[i][0] = 1;
for(int j = 1;j<=i;j++){
c[i][j] = (c[i-1][j-1]*1ll + c[i-1][j])%mod;
}
}
ll ans = 0;
for(int i = sum;i<=m;i++){
ans+=c[i-sum+n-1][n-1];
ans%=mod;
}
cout<<ans<<endl;
}
E.AND
首先看题,肯定要把所有素数筛出来,怎么做到这一步,因为签到t了,所以想了20分钟也没想出来,直到最后半小时看到了时间限制为2s,刚好其中一秒把质数筛跑完,我真**啊,然后筛完之后发现,只有包含2的区间才可能AND为0,所以二分出答案就行了,没有2就输出0,有2就输出区间长度-2。(不知道为什么手搓二分过90.9%,队友用lower_bound过完了)
#include <bits/stdc++.h>
using namespace std;
using ll =long long;
using pii = pair<int,int>;
using tri = tuple<int,int,int>;
const int N = 1e8+10;
bool st[N];//初始默认全部的数都是质数,都没有被筛,质数是false,合数是true
int primes[N];
int cnt;
void linenum(int n){
for(int i = 2;i<=n;i++){
if(!st[i]){//如果这个数是一个质数那么记录下来
primes[cnt] = i;
cnt++;
}
for(int j = 0;primes[j]<=n/i;j++){//遍历所有筛过的质数
st[i*primes[j]] = true;//i*质数将该数(i*质数)筛掉
if(i%primes[j]==0) break;//线性筛法核心,保证每个数字只被筛出一次,用最小质数来实现。
}
}
}
int lfind(int x){
int l = 0;
int r = cnt-1;
while(l<r){
int mid = l+r>>1;
if(primes[mid]>=x){
r = mid;
}else{
l = mid+1;
}
}
return l;
}
int rfind(int x){
int l = 0;
int r = cnt-1;
while(l<r){
int mid = l+r+1>>1;
if(primes[mid]<=x){
l = mid;
}else{
r = mid-1;
}
}
return l;
}
void solve(){
int x,y;
cin>>x>>y;
int l = lfind(x);
int r = rfind(y);
cout<<r-l+1<<' ';
if(primes[l]>2) cout<<"0"<<endl;
else cout<<r-l-1<<endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
linenum(100000005);
int Text_number = 1;
cin>>Text_number;
while(Text_number--) solve();
return 0;
}
I.马拉松
注意到是一棵树,所以x到y之间一定只有一条路径,期间所有的边都是桥,所以只要找到x能到的点并且这个点不在x->y的路径上的点的总数ans1和y能到达的并且不在x->y路径上的点总数ans2,答案就是ans1*ans2.
void dfs(int x,int y,int num)
{
memset(st,0,sizeof st);
queue<int>q;
q.push(x);
while(q.size())
{
int t=q.front();
q.pop();
if(st[t]||t==y) continue;
st[t]=1;
cnt[t]+=num;
for(auto x : e[t])
q.push(x);
}
}