不会 F 的场。
A
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while (t--){
int a,b;
cin>>a>>b;
int f=0;
if (a%2==0 && a/2!=b){
f=1;
}
if (b%2==0 && b/2!=a){
f=1;
}
if (f){
cout<<"Yes\n";
}
else{
cout<<"No\n";
}
}
return 0;
}
B
去重二分。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5+5;
int n;
void solve(){
cin>>n;
vector<int> v;
for (int i=0; i<n; i++){
int x;
cin>>x;
v.push_back(x);
}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
int ans=0;
for (int i=0; i<v.size(); i++){
int mx=v[i]+n-1;
int l=i,r=v.size();
while (l+1<r){
int mid=l+r>>1;
if (v[mid]>mx){
r=mid;
}
else{
l=mid;
}
}
ans=max(ans,l-i+1);
}
cout<<ans<<"\n";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while (t--){
solve();
}
return 0;
}
其实可以双指针的。
C
分别考虑是前一半还是后一半。发现 \(2k-2\mid n-x\) 或 \(2k-2 \mid n+x-2\) 才可以。同时 \(k\ge x\)。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve(){
ll n,x;
cin>>n>>x;
set<ll> st;
ll y=n-x;
for (ll i=1; i*i<=y; i++){
if (y%i==0){
if (i%2==0) st.insert(i);
if ((y/i)%2==0) st.insert(y/i);
}
}
y=n+x-2;
for (ll i=1; i*i<=y; i++){
if (y%i==0){
if (i%2==0) st.insert(i);
if ((y/i)%2==0) st.insert(y/i);
}
}
int cnt=0;
for (auto u : st){
if ((u+2)/2>=x){
cnt++;
}
}
cout<<cnt<<"\n";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while (t--){
solve();
}
return 0;
}
D
\(\mathcal{O}(N+\sum c)\) 做法。记录少了一个组会少掉多少战斗值。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5+5;
ll n,b,X,c[N],mn[N];
void solve(){
cin>>n>>b>>X;
ll tot=0;
for (int i=1; i<=n; i++){
cin>>c[i];
tot+=c[i];
}
for (int i=1; i<=tot; i++){
mn[i]=0;
}
ll sum=0;
for (int i=1; i<=n; i++){
ll qs=c[i]*(c[i]-1)/2;
sum+=qs;
// cout<<c[i]<<"::"<<qs<<"\n";
for (ll j=c[i]-1; j>=1; j--){
ll _x=c[i]/j;
ll y=c[i]%j;
ll x=j-y;
// assert(x+y==j);
ll it=x*_x*(c[i]-_x)+y*(_x+1)*(c[i]-_x-1);
it/=2;
// cout<<_x<<","<<x<<","<<y<<","<<qs<<","<<it<<"\n";
mn[j]+=qs-it;
qs=it;
}
// cout<<",,,"<<"\n";
}
//cout<<sum<<"!\n";
ll ans=0;
for (ll i=tot; i>=1; i--){
ans=max(ans,sum*b-(i-1)*X);
sum-=mn[i-1];
}
cout<<ans<<"\n";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while (t--){
solve();
}
return 0;
}
E
你考虑最少 \(sum\) 也得有 \((x\%y)\times n\),\(y\mid sum-(x\%y)\times n\)。
你考虑你已经有了答案数组,然后数组每项都减去 \((x\%y)\),再除以 \(y\),这个数列一定是 (从 \(x\) 开始的若干项)+(一堆 \(12345\cdots\)组成的,中间以 \(0\) 间隔)。答案不存在是 \(sum<(x\%y)*\times n\) 或 \((sum-(x\%y)\times n)\%y\neq 0\) 或后面放不下了。
可以 \(dp_i\) 设为至少有做少个位置,才可以放得下 \(i\) 个 \(y\)。然后 \(dp_i\) 可以转移:\(dp_i=min\{dp_{i-a_j}+j+1\}\),\(a_j\) 是第 \(j\) 个三角形数。然后就 \(\mathcal{O}(N\sqrt{N})\) 预处理完。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5+5;
int a[500];
int dp[N],ans[N],pth[N];
void init(){
a[1]=1;
int tot;
for (tot=2; a[tot-1]<N; tot++){
a[tot]=a[tot-1]+tot;
}
tot--;
memset(dp,0x3f,sizeof dp);
dp[0]=0;
for (int i=1; i<N; i++){
for (int j=1; j<=tot && a[j]<=i; j++){
if (dp[i]>dp[i-a[j]]+j+1){
dp[i]=dp[i-a[j]]+j+1;
pth[i]=j;
}
}
}
}
void solve(){
ll n,x,y,s;
cin>>n>>x>>y>>s;
ll md=x%y;
ll mn=md*n;
if (s<mn){
cout<<"NO\n";
return;
}
if ((s-mn)%y!=0){
cout<<"NO\n";
return;
}
ll nd=(s-mn)/y;
for (ll i=0; i<=n; i++){
if (i==0 && x!=md){
continue;
}
// 1~i: from 1
ll sum=(x+x+(i-1)*y)*i/2;
sum=(sum-i*md)/y;
if (i==0){
sum=0;
}
if (sum>nd){
break;
}
ll rm=nd-sum;
if (dp[rm]>(n-i)){
continue;
}
// rm is good
ans[1]=x;
for (int j=2; j<=i; j++){
ans[j]=ans[j-1]+y;
}
int tot=i;
int cur=rm;
while (cur){
int p=pth[cur];
ans[++tot]=md;
for (ll j=1; j<=p; j++){
ans[++tot]=j*y+md;
}
cur=cur-a[p];
}
while (tot<n){
ans[++tot]=md;
}
cout<<"YES\n";
for (int i=1; i<=n; i++){
cout<<ans[i]<<" ";
}
cout<<"\n";
//
return;
}
cout<<"NO\n";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
init();
int t;
cin>>t;
while (t--){
solve();
}
return 0;
}