2024武汉ICPC邀请赛B,E,F,I,K

GYM

B: n个数字,可以执行最多n次操作,选择两个数字,一个+x,一个-x,使得最终全部数字或运算结果最小;

发现:

         执行n次操作后,可以改变任何一个数字的大小,只需要报错总和sum不变即可

        枚举二进制位置,从高位到低位即可

#pragma GCC optimize(3,"Ofast","inline")
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll; 
#define int long long
#define ld long double
int n,sum;
void solve()
{ cin>>n;
for(int i=1;i<=n;i++){
	int x;cin>>x;
	sum+=x;
}	int ans=0;
	 for(int i=62;i>=0;i--){//枚举
	 	int ti=(1<<i)-1;
	 	if(ti*n>=sum){//如果剩余位置总和>=num则此位置无需放数字
	 		continue;
	 	}
		int tk=ti+1;
	 	ans+=tk;//此位置是1,则或运算结果,增加
	 	int l=1,r=n;//二分此位置最多可以放的数字个数
	 	while(l<r){
	 		int mid=(l+r+1)/2;
			int to=mid*tk;
			if(to<=sum) l=mid;
			else r=mid-1; 
	 	}
	sum-=tk*l;//总和减少
	 }
	cout<<ans;
}
signed main()
{
	ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
	solve();

	return 0;
}

E:我们发现, 对于每一个K 可以二分时间,对于当前时间点,找出已被传播的边形成的树的最长路径(直径)即可;

lca+动态树的直径

#pragma GCC optimize(3,"Ofast","inline")
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
const int 	N=200010;
#define int long long
#define endl '\n'
int cnt,head[N];
int depth[N];//深度
int fa[N][20];
int q[N],n;
int dp[2*N];
vector<int>s[N*2];
struct edge
{
    int nx;
    int to;
};
edge ed[2*N];
void add(int a,int b)
{
    ed[++cnt].nx=head[a];
    ed[cnt].to=b;
    head[a]=cnt;
}
void bfs(int root)
{   memset(depth,0x3f,sizeof(depth));
    depth[0]=0;depth[root]=1;
    queue<int>q;
    q.push(root);
    while(q.size())
    {
    int t=q.front();
        q.pop();
    for(int i=head[t];i!=-1;i=ed[i].nx)
        {
            int j=ed[i].to;
          if(depth[j]>depth[t]+1)
            {
                depth[j]=depth[t]+1;
                 q.push(j);
             fa[j][0]=t;    
             for(int k=1;k<=18;k++)
                {
                fa[j][k]=fa[fa[j][k-1]][k-1];
                }
            }
        }
    }
    return;
}
int lca(int x,int y)//最近公共祖先
{ 
        if (depth[x] < depth[y]) {
            swap(x, y);
        }
        for (int i = 19; i >= 0; i--)  {
            if(depth[x] - depth[y] >= (1 << i)) {
				x=fa[x][i];
            }
        }
        if (x == y) {
            return x;
        }
        for (int i = 19; i >= 0; i--) {
        	 if(fa[x][i] != fa[y][i]) {
                x = fa[x][i], y = fa[y][i];
            }
        }
        return fa[x][0]; 
}
signed main()
{
    cin>>n;
    int root=0,to;
    memset(head,-1,sizeof(head));
    for(int i=1;i<n;i++)
    {
     int a,b; cin>>a>>b;
 	  add(a,b),add(b,a);
    }
    cin>>root>>to;
    bfs(root);
    for(int i=1;i<=n;i++){
    	s[depth[i]-1].push_back(i);
    }
   	for(int i=1;i<=n+n;i++){
		dp[i]=dp[i-1];
		int sum=0;
		if(s[i].size()) {
			int u=s[i][0];
			for(int j=1;j<s[i].size();j++){
				int v=s[i][j];
				int m=lca(u,v);
		//此两点的距离
				m=depth[u]+depth[v]-2*depth[m];
				sum=max(sum,m);
			}
		//动态求树的直径
			dp[i]=max(dp[i]+1,sum);
		}
   	}  
   		for(int i=1;i<=n;i++){
   			int l=1,r=n;
			while(l<r){
				int mid=(l+r)/2;
				int len=dp[to+mid];
				len=(len+1)/2;
				if(len<=(int)i*mid) r=mid;
				else l=mid+1;
			}
   			cout<<to+l<<" ";
   		}
return 0;
}

F:  交互题,整个二维数组是,从左到右递增,从上到下递增,我们可以二分答案x;

从第一列开始找<=x的个数sum,直到最后一列,判断sum与n*n-k+1 即可

#pragma GCC optimize(3,"Ofast","inline")
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll; 
#define int long long
#define ld long double
int n,k;
int query(int x,int y,int k){
	cout<<"? "<<x<<" "<<y<<" "<<k<<endl;
	int ok;cin>>ok;
	return ok;
}
void solve()
{
	 cin>>n>>k;
	 k=n*n-k+1;
	int l=1,r=n*n;//二分答案
	while(l<r){
		int mid=(l+r)/2;
		int sum=0;
		int now=n;//n列
		for(int i=1;i<=n;i++){
		while(1) {
		if(now==0) break;
		int ok=query(i,now,mid);
		if(ok==0) now--;
		else {
			sum+=now; break;	
		}
			}
			if(sum>=k) break;
		}
		if(sum>=k) r=mid;
		else l=mid+1;
	}	
	cout<<"! "<<l;
}
signed main()
{
	solve();
	return 0;
}

I:

模拟,每次操作可以使得一个全是1的连通块转移到最后面,枚举连通块个数,如果最后一位是1 减去即可

#pragma GCC optimize(3,"Ofast","inline")
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll; 
#define int long long
#define ld long double
void solve()
{
	 string s;cin>>s;
	 int a,ok;
	  ok=0;a=0;
for(int i=0;i<s.size();i++){
	if(ok==1&&s[i]=='1') continue;
	if(s[i]=='0') {ok=0;continue;}
	ok=1,a++;
}
if(ok) a--;
cout<<a;
}
signed main()
{
	ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
	solve();
	return 0;
	}

K 博弈论

我们发现使得1--n全部异或为0,那么1-3为0,  4-7为0,   8-11为0,..... 大于3后,每4位为0

因此枚举上述情况即可;

#pragma GCC optimize(3,"Ofast","inline")
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll; 
#define int long long
#define ld long double
void solve()
{ string z="Fluttershy\n",y="Pinkie Pie\n";
	int n;
	cin>>n;
	if(n==1)  {cout<<z;return;}
	if(n==2) {cout<<y;return;}
	if(n==3) cout<<y;
	else  {
		int ti=n-3;
ti=ti%4;
if(ti==0) {cout<<y;return;}
if(ti==1||ti==2) cout<<z;
else cout<<y;
	}
}
signed main()
{
	ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
	int t; cin>>t;
	while(t--)
{
	solve();
}
	return 0;
}

  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值