Codeforces Round 897 (Div. 2)
让大的数减小的数就可以制造更多的不同。
PII a[N];
int ans[N];
void solve(){
int n=read();
for(int i=1;i<=n;i++){
a[i]=make_pair(read(),i);
}
sort(a+1,a+1+n);
for(int i=1;i<=n;i++){
ans[a[i].second]=(n-i+1);
}
for(int i=1;i<=n;i++){
cout<<ans[i]<<" ";
}
cout<<'\n';
//puts(ans>0?"YES":"NO");
//puts(ans>0?"Yes":"No");
}
首先答案显然对称。
找到最小的变化次数然后依次加
如果是奇数显然可以多变一个中间的数字,填补变一对的的空缺。
void solve(){
int n=read();
string s;
cin>>s;
s=' '+s;
int minn=0;
for(int i=1;i<=n&&i<=n-i+1;i++){
if(s[i]!=s[n-i+1])minn++;
}
if(n%2==0){
for(int i=0;i<=n;i++){
if(minn<=i&&i<=n-minn&&i%2==minn%2){
cout<<1;
}else cout<<0;
}
}else{
for(int i=0;i<=n;i++){
if(minn<=i&&i<=n-minn){
cout<<1;
}else cout<<0;
}
}
cout<<'\n';
//puts(ans>0?"YES":"NO");
//puts(ans>0?"Yes":"No");
}
每次加入
如果想要更大的
int a[N];
void solve(){
int n=read();
for(int i=1;i<=n;i++){
a[i]=read();
}
int cnt=0,op=a[n]+1;
for(int i=1;i<=n;i++){
if(a[i]==cnt)cnt++;
else {
op=cnt;
break;
}
}
while(1){
cout<<op<<endl;
int x;
cin>>x;
if(x==-1)break;
op=x;
}
//puts(ans>0?"YES":"NO");
//puts(ans>0?"Yes":"No");
}
对位置和点权建边,跑强连通。
如果一个点位于单链上,分析可知一定可以完成赋值的,因为总存在一个点不需要对其他点负责,而且也可以多次对一个点覆盖。
如果一个点位于强连通分量上,显然要大小等于
int cnt,low[N],num[N],dfn,sccno[N],sta[N],top;
int siz[N];
vector<int>G[N];
void dfs(int u){
sta[top++]=u;
low[u]=num[u]=++dfn;
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
if(!num[v]){
dfs(v);
low[u]=min(low[v],low[u]);
}else if(!sccno[v]){
low[u]=min(low[u],num[v]);
}
}
if(low[u]==num[u]){
cnt++;
while(1){
int v=sta[--top];
sccno[v]=cnt;
if(u==v)break;
}
}
}
void Tarjan(int n){
cnt=top=dfn=0;
for(int i=1;i<=n;i++){
if(!num[i]){
dfs(i);
}
}
}
void solve(){
int n=read(),k=read(),ans=1;
for(int i=0;i<=n+100;i++){
G[i].clear();
num[i]=0;
sccno[i]=0;
siz[i]=0;
low[i]=0;
}
for(int i=1;i<=n;i++){
int x=read();
G[i].push_back(x);
}
if(k==1){
int ok=1;
for(int i=1;i<=n;i++){
if(G[i][0]!=i)ok=0;
}
puts(ok>0?"YES":"NO");
return ;
}
Tarjan(n);
for(int i=1;i<=n;i++){
siz[sccno[i]]++;
}
for(int i=1;i<=n;i++){
if((siz[sccno[i]]==1&&G[i][0]==i)||(siz[sccno[i]]!=1&&siz[sccno[i]]!=k))ans=0;
}
puts(ans>0?"YES":"NO");
//puts(ans>0?"Yes":"No");
}
对于前面的整块显然是直接询问,对于剩下的数字需与最后一个整块合并,每次询问因为会反转,依次问这个区间就可以得到这个区间的异或和。分析我们的询问次数。前半段最多花费
int ask(int x){
cout<<"? "<<x<<endl;
return read();
}
void solve(){
int n=read(),k=read(),ans=0;
for(int i=1;i+k-1<=n;){
ans^=ask(i);
if(i+k*2-1<=n)i+=k;
else i++;
}
cout<<"! "<<ans<<endl;
//puts(ans>0?"YES":"NO");
//puts(ans>0?"Yes":"No");
}
观察到偶数,说明
int ask(int x){
cout<<"? "<<x<<endl;
return read();
}
void solve(){
int n=read(),k=read(),ans=0;
for(int i=1;i+k-1<=n;i+=k){
ans^=ask(i);
}
if(n%k){
ans^=ask(n-k+1-((n%k)>>1));
ans^=ask(n-k+1);
}
cout<<"! "<<ans<<endl;
//puts(ans>0?"YES":"NO");
//puts(ans>0?"Yes":"No");
}
如果我们已经有一颗小子树不与原图
用树哈希的方式记录原图的出现的树,然后暴力枚举子树大小,寻找没有出现过的树。
那么进一步研究,可以得出枚举到的可行子树大小必然是一个很小的数字。因为
vector<int>G[N],siz,a,b,c;
vector<vector<int> >nxt;
int num,id[N],n,t,cnt,ans,res;
map<vector<int>,int>mp;
int get(vector<int> &a){
if(mp.find(a)!=mp.end()) //若存在
return mp[a]; //返回已有值
int s=1;
for(auto x:a)
s+=siz[x]; //记录子树大小
siz.push_back(s);
nxt.push_back(a); //记录后继节点
int id=mp.size(); //赋值hash
mp[a]=id;
return id;
}
void cal(int sur,int lst){
if(!sur){ //若sur为0
int k=get(b); //对空vec取hash
c.push_back(k); //将hash值记录
if(k>cnt)ans=res,num=k; //如果这个hash值是已记录之外的就是符合要求 记录数据
return ;
}
for(int i=lst;i<a.size();i++){ //递归枚举所有已知子树
if(siz[a[i]]<=sur){ //如果该子树大小小于目前枚举的值
b.push_back(a[i]); //塞入临时vec
cal(sur-siz[a[i]],i); //递归
if(ans)return ; //如果得到合法就return
b.pop_back(); //删掉刚入队的元素
}
}
}
void dfs(int u,int fa){
vector<int> aa; //新建vec
aa.clear();
for(auto v:G[u]){
if(v==fa)continue;
dfs(v,u); //向下递归
aa.push_back(id[v]); //将子节点的编号存入vec
}
sort(aa.begin(),aa.end()); //对vec排序
id[u]=get(aa); //记录hash
cnt=max(cnt,id[u]); //一共有多少个hash值
return ;
}
void pr(int x,int y){
for(auto v:nxt[y]){
int u=++ans;
cout<<u<<" "<<x<<"\n";
pr(u,v);
}
}
void solve(){
n=read();
for(int i=1;i<n;i++){
int u=read(),v=read();
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,0); //对给定的子树作hash
for(res=1;res<=n;res++){
cal(res-1,0); //暴力处理res个节点的时候 所有可能情况
if(ans){ //如果可以
ans=1;
for(int j=n;j>res;j--,ans++){ //把子树之外的树枝随便构造
cout<<ans<<" "<<ans+1<<'\n';
}
pr(ans,num); //递归输出子树
return ;
}
a.insert(a.end(),c.begin(),c.end());
c.clear();
b.clear();
sort(a.begin(),a.end());
}
for(int i=1;i<=n;i++){ //若找不到 输出子树
for(auto j:G[i]){
if(i>j)cout<<i<<" "<<j<<"\n";
}
}
//puts(ans>0?"YES":"NO");
//puts(ans>0?"Yes":"No");
}
本文作者:EdGrass
本文链接:https://www.cnblogs.com/edgrass/p/17694957.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步