2026 暑期每日一题
2026 暑期每日一题
6月25日 P4643 [国家集训队] 阿狸和桃子的游戏
观察到题目要求的是得分之差,如果我们将边权均分给两个点,会惊喜的发现对答案没有任何影响,之后就贪心即可。
代码:
C++
#include
using namespace std;
const int N=1e5+5;
int n,m,ans;
int a[N];
int main(){
cin>>n>>m;
for(int i=1;i>a[i],a[i]>u>>v>>w;
a[u]+=w,a[v]+=w;
}
sort(a+1,a+1+n);
for(int i=1;i>1);
return 0;
}
`#include
using namespace std;
const int N=1e5+5;
int n,m,ans;
int a[N];
int main(){
cin>>n>>m;
for(int i=1;in;i++) cin>>a[i],a[i]1;
for(int i=1;im;i++){
int u,v,w;
cin>>u>>v>>w;
a[u]+=w,a[v]+=w;
}
sort(a+1,a+1+n);
for(int i=1;in;i++) ans+=pow(-1,i)*a[i];
cout(ans>>1);
return 0;
}`
6月26日 P15410 「TBOI Round 1」Niton & Matrix
会发现一个点无论怎么变只可能出现在 这四个位置,并且无论怎么取反都不会影响它们的异或和,所以直接根据这个性质判断即可。
代码:
C++
#include
using namespace std;
const int N=1e5+5;
int n,m;
vector a[N],b[N];
void solve(){
int y=1;
for(int i=0;i>n>>m;
for(int i=1;i>x;
a[i].push_back(x);
}
}
for(int i=1;i>x;
b[i].push_back(x);
}
}
for(int i=1;i>1);i++) for(int j=1;j>1);j++)
if(a[i][j]^a[n-i+1][j]^a[i][m-j+1]^a[n-i+1][m-j+1]!=b[i][j]^b[n-i+1][j]^b[i][m-j+1]^b[n-i+1][m-j+1])
y=0;
cout>T;
while(T--) solve();
return 0;
}
`#include
using namespace std;
const int N=1e5+5;
int n,m;
vectorint> a[N],b[N];
void solve(){
int y=1;
for(int i=0;iN;i++) a[i].clear(),b[i].clear();
cin>>n>>m;
for(int i=1;in;i++){
a[i].push_back(0);
for(int j=1;jm;j++){
int x;
cin>>x;
a[i].push_back(x);
}
}
for(int i=1;in;i++){
b[i].push_back(0);
for(int j=1;jm;j++){
int x;
cin>>x;
b[i].push_back(x);
}
}
for(int i=1;i(n>>1);i++) for(int j=1;j(m>>1);j++)
if(a[i][j]^a[n-i+1][j]^a[i][m-j+1]^a[n-i+1][m-j+1]!=b[i][j]^b[n-i+1][j]^b[i][m-j+1]^b[n-i+1][m-j+1])
y=0;
cout(y?"Yes\n":"No\n");
return;
}
signed main(){
int T;
cin>>T;
while(T--) solve();
return 0;
}`
6月30日 P14511 [NFLSPC #8] 轨道交通
假设最优策略下交点个数为 0。
当我们只管每个点的 坐标,将所有点排序后选最前面两个颜色相等的点,然后把前面的点全部删掉,这样每个颜色不被配对但被删掉的点最多有 个,而每个颜色又有 个点,剩下两个点刚好可以配对,所以按照这样的策略一定能找到最优解。
注意纵坐标并不能忽略,我们在删除之前的点时没有删除与当前点横坐标相等的所有点,所以在横坐标相同的情况下还需要按照纵坐标排序以下,这样彻底规避了线段有交的情况。
代码:
C++
#include
using namespace std;
const int N=1e3+5;
int n,T;
struct node{
int col,x,y,id;
bool operator a;
int ans[N][2],tag[N];
void solve(){
a.clear();
memset(tag,0,sizeof tag);
memset(ans,0,sizeof ans);
cin>>n;
for(int i=1;i>x>>y;
a.push_back({i,x,y,j});
}
sort(a.begin(),a.end());
for(int i=1;i mp;
while(a.size()){
auto[col,x,y,id]=a.front();
a.pop_front();
if(mp[col]==0) mp[col]=id;
else if(!tag[col]){
ans[col][0]=mp[col],ans[col][1]=id;
sort(ans[col],ans[col]+2);
tag[col]=1;
break;
}
}
}
for(int i=1;i>T;
while(T--) solve();
return 0;
}
`#include
using namespace std;
const int N=1e3+5;
int n,T;
struct node{
int col,x,y,id;
bool operatorconst node &a)const{
if(x!=a.x) return xa.x;
return ya.y;
}
};
dequenode> a;
int ans[N][2],tag[N];
void solve(){
a.clear();
memset(tag,0,sizeof tag);
memset(ans,0,sizeof ans);
cin>>n;
for(int i=1;in;i++) for(int j=1;jn+1;j++){
int x,y;
cin>>x>>y;
a.push_back({i,x,y,j});
}
sort(a.begin(),a.end());
for(int i=1;in;i++){
mapint,int> mp;
while(a.size()){
auto[col,x,y,id]=a.front();
a.pop_front();
if(mp[col]==0) mp[col]=id;
else if(!tag[col]){
ans[col][0]=mp[col],ans[col][1]=id;
sort(ans[col],ans[col]+2);
tag[col]=1;
break;
}
}
}
for(int i=1;in;i++) coutans[i][0]" "ans[i][1]"\n";
}
int main(){
cin>>T;
while(T--) solve();
return 0;
}`
7月1日 P15061 琥峪枫
不难发现,可以用 个次数求出:
∑i=1nask(i,1)=3∑i=1nfi−2∑i∈叶子节点fi−froot\sum_{i=1}^{n} ask(i,1) = 3\sum_{i=1}^{n}f_i - 2\sum_{i\in 叶子节点} f_i-f_{root}
再使用 次 得到根节点以及根节点的两个儿子,那 ,叶子节点的权值和根据定义也很好求。
代码:
C++
#include
using namespace std;
const int N=5e5+5;
long long a[N];
long long ask(int u,int d);
long long solve(int subtask,int h){
int n=(1b;
long long ans=0,c0=0,c1=0;
for(int i=1;i
`#include
using namespace std;
const int N=5e5+5;
long long a[N];
long long ask(int u,int d);
long long solve(int subtask,int h){
int n=(1h)-1,rt=-1;
vectorint>b;
long long ans=0,c0=0,c1=0;
for(int i=1;in;i++) ans+=a[i]=ask(i,1);
for(int i=1;in;i++) if(!ask(i,h+1)) b.push_back(i);
if(b.size()3) b.push_back(n);
for(int i=0;i3;i++){
long long x=ask(b[i],h);
if(!x) rt=b[i];
else c0+=a[b[i]],c1+=x;
}
return (ans+(c11)+(c0-ask(rt,2))/2)/3;
}`
7月2日 P15303 『NFC-OI R1』序列陆
先看特殊情况:
1.
直接询问 的数量即可。
2.
先询问 的数量,再二分找到最后一个 的位置,询问次数 ,刚好。
3.
先询问 的数量,记为 。
令 ,若 ,说明所有的 都在最后,直接输出即可。
否则序列应该长下面这个样子:(图中 与输入的 不一致)

再令 ,
若
说明 的位置关系应该如下图:

这时图中的 ,,再和上面一样二分找到最后一个 的位置即可。
若
的位置关系大致如下图:

由上图可知,,那么 ,那就知道了第一个 的位置,从第一个 的位置开始二分,找到最后一个满足 的位置,就相当于找到了 ,那就做出来了。
最后最多询问 ,符合要求。
代码:
C++
#include
using namespace std;
int n,k,c,x;
int ask(int l,int r){
int xx;
cout>xx;
return xx;
}
signed main(){
cin>>n>>k>>c;
if(c==1){
x=ask(1,n);
cout>1;
x=ask(1,mid);
if(x>0) r=mid;
else l=mid+1;
}
int pos=l;
x=ask(1,n);
cout>1;
x=ask(1,mid);
if(x>0) r=mid;
else l=mid+1;
}
int pos=l;
cout>1;
x=ask(pos+1,pos+mid);
if(x==mid) l=mid;
else r=mid-1;
}
cout
`#include
using namespace std;
int n,k,c,x;
int ask(int l,int r){
int xx;
cout"? "l" "rendl;
cin>>xx;
return xx;
}
signed main(){
cin>>n>>k>>c;
if(c==1){
x=ask(1,n);
cout"! ";
for(int i=1;in-x;i++) cout"0 ";
for(int i=1;ix;i++) cout"1 ";
coutendl;
return 0;
}
else if(c==2){
int l=1,r=n;
while(lr){
int mid=(l+r)>>1;
x=ask(1,mid);
if(x>0) r=mid;
else l=mid+1;
}
int pos=l;
x=ask(1,n);
cout"! ";
for(int i=1;ipos;i++) cout"0 ";
for(int i=1;ix;i++) cout"1 ";
for(int i=pos+x;in;i++) cout"0 ";
coutendl;
return 0;
}
int a,b;
a=ask(1,n);
b=ask(n-a+1,n);
if(a==b){
cout"! ";
for(int i=1;in-a;i++) cout"0 ";
for(int i=1;ia;i++) cout"1 ";
coutendl;
return 0;
}
c=ask(n-b+1,n);
if(b==c){
int l=1,r=n;
while(lr){
int mid=(l+r)>>1;
x=ask(1,mid);
if(x>0) r=mid;
else l=mid+1;
}
int pos=l;
cout"! ";
for(int i=1;ipos-1;i++) cout"0 ";
for(int i=1;ia-b;i++) cout"1 ";
for(int i=1;in-a-pos+1;i++) cout"0 ";
for(int i=1;ib;i++) cout"1 ";
coutendl;
return 0;
}
else{
int zero=a-b,pos=n-a-zero;
int l=1,r=a;
while(lr){
int mid=(l+r+1)>>1;
x=ask(pos+1,pos+mid);
if(x==mid) l=mid;
else r=mid-1;
}
cout"! ";
for(int i=1;ipos;i++) cout"0 ";
for(int i=1;il;i++) cout"1 ";
for(int i=1;izero;i++) cout"0 ";
for(int i=1;ia-l;i++) cout"1 ";
coutendl;
return 0;
}
return 0;
}`