完整版题目点这里 下面题目标题的蓝链需要付费才能打开 可以提交代码
这场做的挺难受的 B题一直没guess出来 节奏打乱之后就狠狠难受了
L - 数独x扫雷
题意
给你一个9*9的填好的数独矩阵 要求你替换其中部分数字为*表示地雷 使得新的矩阵满足扫雷的规则即数字周围的地雷数等于该数字
思路
因为是数独矩阵 所以在中间的那个3*3的矩阵内一定包括1~9的所有数字 其中自然也就会有8 除了这个8的所有数字都改成地雷 一定可以满足条件
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void solve()
{
string s[9];
for(int i=0;i<9;i++)
{
cin>>s[i];
}
pii save;
for(int i=3;i<6;i++)
{
for(int j=3;j<6;j++)
{
if(s[i][j]=='8')
save={i,j};
}
}
for(int i=0;i<9;i++)
{
for(int j=0;j<9;j++)
{
if(i==save.first and j==save.second)
cout<<s[i][j];
else
cout<<'*';
}
cout<<endl;
}
}
int main()
{
int T=1;
//scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}
B - 碰撞测试
题意
给n种数量无限的助推器 每种可以让车辆往前推进h[i]米 初始位置前方D米处有一堵墙 撞上墙后剩余的距离会反弹回来 之后还可以继续推进 问整个过程可能到达的与墙最近的位置是哪里
思路
赛时主要是guess 像我们这种guess不出来的只能说确实是命里没这道题
总之就是所有h求gcd然后跟D取余 再逆元考虑一下正负即可
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void solve()
{
ll n,D;
scanf("%lld%lld",&n,&D);
ll tmp;
scanf("%lld",&tmp);
for(int i=1;i<n;i++)
{
ll x;
scanf("%lld",&x);
tmp=__gcd(tmp,x);
}
printf("%lld\n",min(D%tmp,tmp-D%tmp));
}
int main()
{
int T=1;
//scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}
A - 过桥
题意
n个人过桥 每个人都有一个体力值 只有一艘船 每次最少载L人最多载R人 每坐船过一次河就要消耗船上所有人1点体力 问有没有办法让所有人过河
复盘
考虑贪心 每次都是体力最多的R个人过去 然后体力更多的L个人回来 直到走不了为止 用两个set不难模拟这种情况 但是赛时这么写没有过
#include<bits/stdc++.h>
using namespace std;
const long long N=1e7+20;
map<long long,long long>mp;
long long ma=1e9,k,n;
const long long inf=1e18;
multiset<long long>l,r;
void solve()
{
long long i,j,m,ans=0,temp,sum=0,L,R;
cin>>n>>L>>R;
for(i=1;i<=n;i++)
{
cin>>k;
l.insert(k);
}
l.insert(inf);
l.insert(-inf);
r.insert(inf);
r.insert(-inf);
/*
for(auto now=l.begin();now!=l.end();now++)
cout<<*now;
cout<<endl;*/
if(R==n)
{
cout<<"Yes";
return;
}
ans=l.size();
sum=r.size();
bool flag=false;
while(ans>2)
{
if(!flag)
{
auto it=l.end();
it--;
if(it==l.begin())
{
cout<<"No";
return;
}
it--;
if(it==l.begin())
{
cout<<"Yes";
return;
}
temp=*it;
//cout<<temp<<endl;
l.erase(it);
it=l.end();
it--;
if(it==l.begin())
{
cout<<"No";
return;
}
it--;
if(it==l.begin())
{
cout<<"Yes";
return;
}
temp--;
if(temp>1)
r.insert(temp);
if(R+2>=ans&&ans>=L+2)
{
cout<<"Yes";
return;
}
else if(ans<L+2)
{
cout<<"No";
return;
}
else
{
for(i=1;i<R;i++)
{
auto down=l.begin();
down++;
if(down==l.end())
{
if(i<L)
cout<<"No";
else
cout<<"Yes";
return;
}
temp=*down;
l.erase(down);
//cout<<temp<<endl;
temp--;
if(temp>1)
r.insert(temp);
}
}
}
else
{
if(r.size()<L+2)
{
cout<<"No";
return;
}
for(i=1;i<=L;i++)
{
auto it=r.end();
it--;
if(it==r.begin())
{
cout<<"No";
return;
}
it--;
if(it==r.begin())
{
cout<<"No";
return;
}
temp=*it;
r.erase(it);
// cout<<temp<<endl;
temp--;
if(temp)
l.insert(temp);
}
}
flag=!flag;
//cout<<flag<<endl;
//cout<<ans<<endl;
ans=l.size();
}
cout<<"Yes";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
long long t=1;
//cin>>t;
while(t--)
solve();
}
思路
首先是去一个来回就是要从总体力值中消耗(L+R)点 那么划船回来的次数一共是 再对于一个人而言 他过去一次至少要消耗1体力 多余的体力可以用来跑个来回 那么可以得到每个人多跑的来回数(其中超过S的次数没有意义)就一定比回来消耗的总体力多 也就是满足 然后照着公式敲就可以了
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void solve()
{
ll n,L,R;
scanf("%lld%lld%lld",&n,&L,&R);
ll S=(n-R)/(R-L);
if((n-R)%(R-L)!=0) S++;
ll sum=0;
for(int i=0;i<n;i++)
{
ll h;
scanf("%lld",&h);
ll a=(h-1)/2;
sum+=min(a,S);
}
if(sum>=S*L)
printf("Yes\n");
else
printf("No\n");
}
int main()
{
int T=1;
//scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}
J - 打假赛
可以点这里免费提交
题意
两队赢一局积一点小积分 先积到a点小积分则这一队积一点大积分 同时重置两队积分 先攒到b点大积分的队伍获胜 两队的胜负依据字符串给定的情况无限循环下去 问从字符串1~n位开始计算分别是哪一队获胜
复盘
赛时写的是一个dfs 然后过大的时候可以一批一批加上去 事实证明优化程度小到可怜
不过还是丢上来吧 不管怎么说 看我那些注释也知道我调了老半天了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void solve()
{
int n,a,b;
scanf("%d%d%d",&n,&a,&b);
string s;
cin>>s;
for(int i=0;i<n;i++)
{
vector<int> s1;
int end=i-1;
if(end<0) end=n-1;
int a1=0,b1=0;
int j=i;
// printf("end=%d\n",end);
int a3=0,b3=0;
int flag=0;
while(1)
{
if(j==n) j=0;
if(s[j]=='0') b1++;
else a1++;
if(a1>=a)
{
s1.push_back(1);
a1=0;
b1=0;
a3++;
// printf("j=%d now=1\n",j);
// printf("1");
if(j==end) break;
}
else if(b1>=a)
{
s1.push_back(0);
a1=0;
b1=0;
b3++;
// printf("j=%d now=0\n",j);
// printf("0");
if(j==end) break;
}
if(a3==b)
{
printf("1");
flag=1;
break;
}
else if(b3==b)
{
printf("0");
flag=1;
break;
}
j++;
}
if(flag) continue;
// printf("\n");
j=0;
int a2=0,b2=0;
end=s1.size();
while(1)
{
if(j==end) j=0;
if(s1[j]==0) b2++;
else a2++;
if(a2>=b)
{
printf("1");
break;
// s2.push_back(1);
// a2=0;
// b2=0;
// printf("1");
// if(j==end) break;
}
else if(b2>=b)
{
printf("0");
break;
// s2.push_back(0);
// a2=0;
// b2=0;
// printf("0");
// if(j==end) break;
}
j++;
}
// printf("\n");
}
}
int main()
{
int T=1;
//scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}
思路 by Caikun_chen
见代码
代码
#include<bits/stdc++.h>
using namespace std;
const long long N=1e5+20;
long long sa[N][22],sb[N][22];//sa记录字符串中1的个数,sb记录0的个数
long long nxt[N][22];//记录下一场开始的位置
long long ta[N][22],tb[N][22];//记录大比分
long long nyt[N][22];//记录下一场大比分开始的位置
void solve()
{
long long i,j,k,n,m,a,b;
string s;
cin>>n>>a>>b;//a小局,b大局
cin>>s;
for(i=0;i<n;i++)
{
nxt[i][0]=(i+1)%n;
if(s[i]=='1')
sa[i][0]++;
else
sb[i][0]++;
}
for(j=1;j<=20;j++)//倍增初始化了(小局)
{
for(i=0;i<n;i++)
{
nxt[i][j]=nxt[nxt[i][j-1]][j-1];
sa[i][j]=sa[i][j-1]+sa[nxt[i][j-1]][j-1];
sb[i][j]=sb[i][j-1]+sb[nxt[i][j-1]][j-1];
}
}
for(i=0;i<n;i++)//求位置i开始的小局情况
{
long long lx=0,ly=0;
long long now=i;//记录当前位置
for(j=20;j>=0;j--)
{
if(lx+sa[now][j]<a&&ly+sb[now][j]<a)//小于比分的时候相加
{
lx+=sa[now][j];
ly+=sb[now][j];
now=nxt[now][j];
}
}
lx+=sa[now][0];//加回s[now]的比分,与上文小于a,而不是小于等于a形成对应
ly+=sb[now][0];//更好判断决胜局的情况
now=nxt[now][0];
nyt[i][0]=now;
if(lx==a)
ta[i][0]=1;
else
tb[i][0]=1;
}
for(j=1;j<=20;j++)//倍增初始化(大局)
{
for(i=0;i<n;i++)
{
nyt[i][j]=nyt[nyt[i][j-1]][j-1];
ta[i][j]=ta[i][j-1]+ta[nyt[i][j-1]][j-1];
tb[i][j]=tb[i][j-1]+tb[nyt[i][j-1]][j-1];
}
}
for(i=0;i<n;i++)
{
long long lx=0,ly=0;
long long now=i;
for(j=20;j>=0;j--)
{
if(lx+ta[now][j]<b&&ly+tb[now][j]<b)//小于比分的时候相加
{
lx+=ta[now][j];
ly+=tb[now][j];
now=nyt[now][j];
}
}
lx+=ta[now][0];//加回s[now]的比分,与上文小于a,而不是小于等于a形成对应
ly+=tb[now][0];//更好判断决胜局的情况
if(lx==b)
cout<<1;
else
cout<<0;
}
}
int main(){
long long t=1;
//cin>>t;
while(t--)
solve();
return 0;
}