Lg 8月赛(构造+交互)
Div2
得分 \(270pts' = 100 + 100 + 0 +70\)
打表找规律,大概是每 6 个一个周期。
正经做法是用矩阵加速维护指数,同时用扩展欧拉定理处理模数
#include<bits/stdc++.h>
using namespace std;
#define int long long
template<typename _T>
inline void read(_T &x)
{
x=0;char s=getchar();int f=1;
while(s<'0'||s>'9') {f=1;if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
x*=f;
}
int a[2333333];
//int a1[23333],a2[23333];
int n,m,k;
signed main()
{
read(n);
read(m);
read(k);
a[1]= n;
a[2] = m;
for(int i=3;i<=100;i++) a[i] = a[i-1] * a[i-2] % 10;//,cout<<a[i]<<" ";
int op = k;
k-= 2;
if(k <= 6) printf("%lld\n",a[2 + k]);
else
{
k = k % 6;
if(!k) k = 6;
printf("%lld\n",a[2 + k]);
}
// printf("%lld",a[op]);
}
贪心就行,用 deque 来维护。(还重构了一次
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pb push_back
template<typename _T>
inline void read(_T &x)
{
x=0;char s=getchar();int f=1;
while(s<'0'||s>'9') {f=1;if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
x*=f;
}
const int INF = 1e18;
const int np = 1e5 + 5;
int a[np];
int b1[np],b2[np],b3[np],b4[np];
int t1,t2,t3,t4;
deque<int> fu[2],zh[2];
inline int Abs(int x){return x < 0?-x:x;}
inline bool cmp(int a,int b)
{
return Abs(a) > Abs(b);
}
signed main()
{
int n;
read(n);
for(int i=1;i<=n;i++) read(a[i]);
sort(a + 1,a + 1 + n);
for(int i=1;i<=n;i++)
{
if(a[i] < 0)
{
int op = Abs(a[i]);
if(op & 1) b1[++t1] = a[i];//fu[1].pb(a[i]);
else b2[++t2] = a[i];//fu[0].pb(a[i]);
}
else
{
int op = Abs(a[i]);
if(op & 1) b3[++t3] = a[i];//zh[1].pb(a[i]);
else b4[++t4] = a[i];//zh[0].pb(a[i]);
}
}
sort(b1 + 1,b1 + 1 + t1,cmp);//1
for(int i=1;i<=t1;i++) fu[1].pb(b1[i]);
sort(b2 + 1,b2 + 1 + t2,cmp);//2
for(int i=1;i<=t2;i++) fu[0].pb(b2[i]);
sort(b3 + 1,b3 + 1 + t3,cmp);//3
for(int i=1;i<=t3;i++) zh[1].pb(b3[i]);
sort(b4 + 1,b4 + 1 + t4,cmp);//4
for(int i=1;i<=t4;i++) zh[0].pb(b4[i]);
int Ans = 0;
for(int i=1;i<=n;i++)
{
if(i & 1)
{
int op1 = zh[0].size() ? zh[0].front():-INF;
int op2 = fu[1].size() ? fu[1].front():-INF;
if(op1 == -INF && op2 == -INF)
{
op1 = zh[1].size() ? zh[1].back():-INF;
op2 = fu[0].size() ? fu[0].back():-INF;
if((op1 != -INF && op2 != -INF && op1 < Abs(op2)) ||(op1!=-INF && op2 == -INF))
{
Ans += op1;
Ans -= (n-i) * op1;
zh[1].pop_back();
}
if((op1!=-INF&&op2!=-INF&&op1 > Abs(op2))||(op1==-INF && op2!=-INF))
{
Ans += op2;
Ans += (n-i) * op2;
fu[0].pop_back();
}
continue;
}
if((op1 != -INF && op2 != -INF && op1 > Abs(op2)) ||(op1!=-INF && op2 == -INF))
{
Ans += op1;
Ans += (n-i) * op1;
zh[0].pop_front();
}
if((op1!=-INF&&op2!=-INF&&op1 < Abs(op2))||(op1==-INF && op2!=-INF))
{
Ans += op2;
Ans += (n-i) * Abs(op2);
fu[1].pop_front();
}
}
else
{
int op1 = zh[1].size() ? zh[1].front():-INF;
int op2 = fu[0].size() ? fu[0].front():-INF;
if(op1 == -INF && op2 == -INF)
{
op1 = zh[0].size() ? zh[0].back():-INF;
op2 = fu[1].size() ? fu[1].back():-INF;
if((op1 != -INF && op2 != -INF && op1 < Abs(op2)) ||(op1!=-INF && op2 == -INF))
{
Ans += op1;
Ans -= (n-i) * op1;
zh[0].pop_back();
}
if((op1!=-INF&&op2!=-INF&&op1 > Abs(op2))||(op1==-INF && op2!=-INF))
{
Ans += op2;
Ans += (n-i) * op2;
fu[1].pop_back();
}
continue;
}
if((op1 != -INF && op2 != -INF && op1 > Abs(op2)) ||(op1!=-INF && op2 == -INF))
{
Ans += op1;
Ans += (n-i) * op1;
zh[1].pop_front();
}
if((op1!=-INF&&op2!=-INF&&op1 < Abs(op2))||(op1==-INF && op2!=-INF))
{
Ans += op2;
Ans += (n-i) * Abs(op2);
fu[0].pop_front();
}
}
}
printf("%lld",Ans);
}
T3「PMOI-4」可怜的团主
太菜了,图上二选一都没做过。
这里给出做法:
首先对原图建出 DFS 树,然后将叶子结点取出。记叶子结点个数为 \(L\),如果 \(L \geq \lfloor\frac{n}{3}\rfloor\),直接取出叶子作为独立集。
若小于,则先在叶子集合中加入根节点,若\(L+1 \mod 2=1\),则再加入一次根节点。
然后按 \(dfn\) 序排序,将 \(i\) 和 \(mid + i\) 进行配对,形成不超过 \(\lceil\frac{n}{6}\rceil\) 条路径
证明正确性:
考虑一个点,若叶子全在它的子树内,那么总会有某个点和根配对,从而导致这个点被覆盖。
若只有一部分叶子在它的子树内,那么一定存在一些叶子和子树外面的叶子匹配,从而导致这个点被覆盖。
综上所述,所有的点都会被覆盖。
#include<bits/stdc++.h>
using namespace std;
template<typename _T>
inline void read(_T &x)
{
x=0;char s=getchar();int f=1;
while(s<'0'||s>'9') {f=1;if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
x*=f;
}
const int np = 1e3 + 5;
const int mp = 1e6 + 5;
int n,m;
int head[np],ver[mp * 2],nxt[mp * 2],tit;
int vis[np],dfn[np],leaf[np],lim,top;
int qaq[np],dep[np],f[20][np],lg[np],sta[np],arc[np];
inline void add(int x,int y)
{
ver[++tit] = y;
nxt[tit] = head[x];
head[x] = tit;
}
inline void dfs(int x,int ff)
{
vis[x] = 1,dfn[x] = ++ lim;
dep[x] = dep[ff] + 1;
f[0][x] = ff;
int son(0);
for(int i=head[x],v;i;i=nxt[i])
{
v = ver[i];
if(vis[v]) continue;
son++;
dfs(v,x);
}
if(!son) leaf[++top]=x;
}
inline int lca_(int u,int v)
{
if(dep[u] < dep[v]) swap(u,v);
int delta = dep[u] - dep[v];
for(int i=lg[delta];i>=0;i--)
if(dep[f[i][u]] >= dep[v]) u = f[i][u];
if(u == v) return u;
delta = dep[v];
for(int i=lg[delta];i>=0;i--)
if(f[i][u]!=f[i][v]) u = f[i][u],v = f[i][v];
return f[0][u];
}
inline bool cmp(int a,int b)
{
return dfn[a] < dfn[b];
}
int qcnt=0;
inline void gets(int op,int ed)
{
qcnt++;
int lca = lca_(op,ed);
int step = 0,arcstep(0);
while(op != lca) sta[++step] = op,op = f[0][op];
sta[++step] = lca;
while(ed != lca) arc[++arcstep] = ed,ed = f[0][ed];
reverse(arc + 1,arc + 1 + arcstep);
printf("%d ",step + arcstep);
for(int i=1;i<=step;i++) printf("%d ",sta[i]);
for(int i=1;i<=arcstep;i++) printf("%d ",arc[i]);
printf("\n");
}
signed main()
{
read(n);
read(m);
for(int i=2;i<=n;i++) lg[i] = lg[i >> 1] + 1;
for(int i=1,a,b;i<=m;i++)
{
read(a);
read(b);
add(a,b);
add(b,a);
}
dfs(1,0);
for(int i=1;i<=lg[n];i++)
for(int j=1;j<=n;j++)
f[i][j] = f[i-1][f[i-1][j]];
if(top >= (n/3))
{
printf("2\n");
for(int i=1;i<=(n/3);i++)
printf("%d ",leaf[i]);
return 0;
}
// int son(0);
// for(int i=head[1];i;i=nxt[i]) son++;
// if(son == 1) leaf[++top] = 1;
leaf[++top] = 1;
if(top & 1) leaf[++top] = 1;
sort(leaf + 1,leaf + 1 + top,cmp);
printf("1\n");
for(int i=1;i<=top/2;i++)
{
int gol = i + top/2;
gets(leaf[i],leaf[gol]);
}
for(int i=2;i<=n;i++)
{
if(qcnt < (n + 5)/6)
{
printf("%d %d\n",1,i);
qcnt++;
}
}
return 0;
}
交互题。
我们要求出 \(l\) 到 \(r\) 之间的序列,先二分中点 \(mid\) 递归处理 \(l\) 到 \(mid\)。我们已知 \(mid\) 的位置,可以直接用 \(mid\) 对 \([mid+1,r]\) 这段区间做询问一,然后这样就做完了。
#include<bits/stdc++.h>
using namespace std;
//#define int long long
#define pb push_back
template<typename _T>
inline void read(_T &x)
{
x=0;char s=getchar();int f=1;
while(s<'0'||s>'9') {f=1;if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
x*=f;
}
const int np = 5e4 + 5;
int a[np];
int bit[20][np];
int xx[np],yy[np];
int aux[np],arc[np];
//vector<>
int n,m1,m2,m3;
inline void solve4()
{
int l(0);
// printf("? 4 3 ");
cout<<"? "<<4<<" ";
for(int i=1;i<=4;i++)cout<<i<<" ";// printf("%lld ",i);
cout<<"3"<<endl;
// printf("4\n");
// fflush(stdout);
// read(l);
// scanf("%lld",&l);
read(l);
for(int i=1;i<=l;i++) read(xx[i]),yy[xx[i]]=1;
int top = 0;
for(int i=1;i<=n;i++)
{
if(yy[i] == 0)aux[++top] = i;
}
for(int i=1;i<=2;i++)
{
for(int q=1;q<=2;q++)
{
int ams;
printf("! %d %d\n",xx[q],aux[i]);
fflush(stdout);
// read(ams);
scanf("%d",&ams);
if(ams)
{
a[aux[i]] = 2;
arc[2] = aux[i];
a[xx[q]] = 3;
arc[3] = xx[q];
if(i == 1) a[aux[i + 1]] = 1,arc[1] = aux[i + 1];
if(i == 2) a[aux[i - 1]] = 1,arc[1] = aux[i - 1];
if(q == 1) a[xx[q + 1]] = 4,arc[4] = xx[q + 1];
if(q == 2) a[xx[q - 1]] = 4,arc[4] = xx[q - 1];
printf("A ");
for(int j=1;j<=3;j++) printf("%d ",a[j]);
printf("%d",a[4]);
fflush(stdout);
return ;
}
}
}
}
inline void solve(int dep,int l,int r,vector<int> vec) // [l,r] ºÍÕâ¸öÇø¼äÄÚµÄÊý
{
int mid = l + r >> 1,lim(0);
vector<int> nxt;
if(r-l+1==4)
{
printf("? 4 ");
int op = -1;
for(auto i:vec) printf("%d ",i),bit[dep][i] += 1;
printf("3\n");
fflush(stdout);
read(l);
for(int i=0;i<l;i++) read(aux[i]),bit[dep][aux[i]] += 1;
for(int i=1;i<=n;i++) if(bit[dep][i] == 1) xx[++op] = i;
for(int i=0;i<=op;i++)
{
for(int j=0,qans;j<l;j++)
{
printf("! %d %d\n",aux[j],xx[i]);
fflush(stdout);
read(qans);
if(qans)
{
a[xx[i]] = 2;
a[aux[j]] = 3;
arc[2] = xx[i];
arc[3] = aux[j];
a[xx[i ^ 1]] = 1;
arc[1] = xx[i ^ 1];
a[aux[j ^ 1]] = 4;
arc[4] = aux[j ^ 1];
return;
}
}
}
}
if(l == r)
{
for(auto i:vec)a[i] = l,arc[l] = i;
return;
}
printf("? %d ",r-l+1);
for(auto i:vec) printf("%d ",i),bit[dep][i] = 1;
printf("%d\n",mid + 1);
fflush(stdout);
read(lim);
for(int i=1,x;i<=lim;i++) read(x),bit[dep][x] += 1;
for(int i=1;i<=n;i++) if(bit[dep][i] == 1) nxt.pb(i);
solve(dep + 1,l,mid,nxt);
for(int i=1,qans;i<=n;i++)
{
if(bit[dep][i] == 2)
{
printf("! %d %d\n",i,arc[mid]);//ax > ay
fflush(stdout);
read(qans);
if(!qans) a[i] = 2 * mid;
else a[i] = mid + qans;
arc[a[i]] = i;
}
}
return ;
}
inline void kkk(int l,int r)
{
printf("%d %d\n",l,r);
if(l == r) return;
int mid = l + r >> 1;
kkk(l,mid);
}
signed main()
{
// kkk(1,5e2);
scanf("%d%d%d%d",&n,&m1,&m2,&m3);
if(n == 4)
{
solve4();
return 0;
}
vector<int> q;
for(int i=1;i<=n;i++) q.pb(i);
solve(1,1,n,q);
printf("A ");
for(int i=1;i<=n;i++)
printf("%d ",a[i]);
fflush(stdout);
}
补完一场 div2。