K 小L的游戏1
思路:
问最后一次操作是谁进行的,先计算一下最多能进行多少次两人操作,然后再看是增加 m 超过 z 还是增加 m+n 超过 z。
代码:
cpp
void solve()
{
int m,n,z;
cin>>m>>n>>z;
int cnt=(z-1)/(m+n);
int ans=cnt*(m+n);
if(ans+m>=z)cout<<"0";
else cout<<"1";
}
H 小L的数组
思路:
一共就两种操作,按位异或是不会超过 2048 的所以开个 2048 的数组就可以。用 dp[i] 来表示这个数字能否到达,然后进行 n 步操作,每一步操作都有一个内循环去处理之前操作所能到达的值。注意不要在内循环中直接去修改 dp 数组这样会导致错误,所以先用一个 ne 数组去存储。
然后从大到小找所能到达的最大值即可。
代码:
cpp
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define endl '\n'
const int N=2100;
int a[N],b[N];
bool dp[2048],ne[2048];
void solve()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<=n;i++)
{
cin>>b[i];
}
memset(dp,0,sizeof dp);
dp[0]=1;
for(int i=1;i<=n;i++)
{
memset(ne,0,sizeof ne);
for(int x=0;x<2048;x++)
{
if(!dp[x])continue;
int m=max(0LL,x-a[i]);
ne[m]=1;
m=x^b[i];
ne[m]=1;
}
for(int j=0;j<2048;j++)
dp[j]=ne[j];
}
for(int i=2047;i>=0;i--)
{
if(dp[i]){
cout<<i;
break;
}
}
}
signed main()
{
int t=1;
IOS
while(t--)
{
solve();
}
}
G 小L的散步
思路:
首先先来个起步检测,如果一开始就踩缝隙了,直接 YES,用前缀和数组+二分查找来进行之后的判断,用前缀和可以记录每个缝隙的位置,二分去找第一个大于后脚跟的缝隙,之后判断是否猜到缝隙。不要暴力,会超时。
代码:
cpp
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define endl '\n'
const int N=2e5+5;
int a[N],b[N],s[N];
void solve()
{
int n,m,l;
cin>>n>>m>>l;
s[0]=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
s[i]=s[i-1]+a[i];
}
for(int i=1;i<=m;i++)
{
cin>>b[i];
}
if(l>a[1])
{
cout<<"YES";
return;
}
int last=0;
for(int i=1;i<=m;i++)
{
last+=b[i];
int le=1,r=n,j=-1;
while(le<=r)
{
int mid=(le+r)/2;
if(s[mid]>=last){
j=mid;
r=mid-1;
}else{
le=mid+1;
}
}
if(j!=-1&&s[j]<last+l&&s[j]>last)
{
cout<<"YES";
return;
}
// for(int j=1;j<=n;j++)
// {
// if(s[j]>last&&s[j]<last+l)
// {
// cout<<"YES";
// return;
// }
// }
}
cout<<"NO";
}
signed main()
{
int t=1;
IOS
while(t--)
{
solve();
}
}
B 小L的彩球
思路:
要有 t 根线其实就是把这 n 个球分成 t+1 块,有两种情况,奇数块归左边或者是奇数块归右边。所以可以计算出左右两盒的块数,奇数块数在计算时需要上取整。然后其实就是在左边 x 个球中划分出 l 个块,就是 Cl−1x−1C^{x-1}{l-1}Cl−1x−1,右边是 Cr−1y−1C^{y-1}{r-1}Cr−1y−1。反之同理。
组合数的计算可以等之后会发一篇简单数学。
代码:
cpp
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define endl "\n"
const int MOD=998244353;
const int N=1e6+5;
int fact[N],infact[N];
int qmi(int a,int b)
{
int res=1;
while(b)
{
if(b&1){
res=a*res%MOD;
}
b>>=1;
a=a*a%MOD;
}
return res;
}
void pre()
{
fact[0]=infact[0]=1;
for(int i=1;i<N;i++)
{
fact[i]=fact[i-1]*i%MOD;
// infact[i]=infact[i-1]*qmi(i,MOD-2)%MOD;
}
infact[N-1]=qmi(fact[N-1],MOD-2);
for(int i=N-2;i>=0;i--){
infact[i]=infact[i+1]*(i+1)%MOD;
}
}
int C(int n,int k)
{
if(k<0||k>n)return 0;
return fact[n]*infact[k]%MOD*infact[n-k]%MOD;
}
void solve()
{
int n,x,t;
cin>>n>>x>>t;
if(t==0){
if(x==0||(n-x)==0){
cout<<"1"<<endl;
}else cout<<"0"<<endl;
return;
}
int k=t+1;
int ans=0;
int l=(k+1)/2,r=k/2;
if(l<=x&&r<=n-x&&l>0&&r>0){
ans=(ans+C(x-1,l-1)*C(n-x-1,r-1)%MOD)%MOD;
}
if(r<=x&&l<=n-x&&l>0&&r>0){
ans=(ans+C(x-1,r-1)*C(n-x-1,l-1)%MOD)%MOD;
}
cout<<ans<<endl;
}
signed main(){
IOS
int T;
cin>>T;
pre();
//int t=1;
while(T--)
{
solve();
}
}
A 小L的三角尺
思路:
考察数学的,首先明确三角形的斜边长度是两直角边的平方和。
那么打磨后的斜边长为 (x2+(y−t)2)\sqrt{(x^2+(y-t)^2)}(x2+(y−t)2) ,对这个函数对 t 求导得 −y−t(x2+(y−t)2)-\frac{y-t}{\sqrt{(x^2+(y-t)^2)}}−(x2+(y−t)2) y−t。
可以把这个看成一个单位贡献值,也就是打磨 1 单位长度后斜边减少多少。这个值随着 t 得增加而减少。
将这个单位贡献值从大到小进行排列,每次打磨一单位后重新计算。用优先队列来存储。
然后就是简单的计算了,最后一个循环把现在的斜边长计算出来。
cpp
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define x first
#define y second
#define endl "\n"
#define PII pair<double,int>
const int N=5e5+5;
int a[N],b[N];
double r[N];
double cal(int i)//用来计算单位贡献值
{
if(r[i]<=0)return 0.0;
else return r[i]/sqrt(1.0*a[i]*a[i]+r[i]*r[i]);
}
void solve()
{
int n,w;
cin>>n>>w;
double sum=0;
int total=0;
int aa=0;
for(int i=1;i<=n;i++)
{
cin>>a[i]>>b[i];
r[i]=b[i];
aa+=a[i];
total+=b[i];
sum+=sqrt(1.0*a[i]*a[i]+1.0*b[i]*b[i]);
}
if(w>=total){//惊天刚试了一下这个特判可以不用
cout<<fixed<<setprecision(9)<<aa;
return;
}
priority_queue<PII> p;//大根堆所以不用greater<>
for(int i=1;i<=n;i++)
{
p.push({cal(i*1LL),i});
}
while(w&&!p.empty())
{
auto [f,i]=p.top();//取出当前最高贡献的
p.pop();
if(f=0)break;
if(r[i]<=0)continue;
w--;//打磨一单位
r[i]--;//打磨一单位
p.push({cal(i*1LL),i});//重新计算贡献后入队
}
double ans=0;
for(int i=1;i<=n;i++)
{
ans+=sqrt(1.0*a[i]*a[i]+r[i]*r[i]);
}
cout<<fixed<<setprecision(9)<<ans;
}
signed main(){
IOS
int t=1;
while(t--)
{
solve();
}
}
🤔为什么把上一个题代码复制后总忘记改 N,罚时比我重写一遍都长。😭😭
看了 WIDA 的验题考虑后补 DE 吧