【补题计划】Codeforces Round #533+#534(Div.2)

本文详细分析了Codeforces Round #533和#534中涉及到的算法问题,包括D. Kilani and the Game的分轮DFS模拟和E. Helping Hiasat的最大独立集转换。同时,讨论了#534中的D. Game with modulo,如何通过交互询问和数学性质确定模数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#533
D. Kilani and the Game
模拟一个游戏,每轮每个玩家可以把距离他拥有的领地的ki步内的格子占领,不能跨越别人的领地以及障碍,问最终每个人占领多少个格子。

写了好几种写法,然后调完才发现是不对的。
最终写了分轮dfs,每个人都有一个bfs队列。对于每一轮知道玩家占领格子的最远距离,当队列头是这些格子时就break出去,下一轮才会考虑从这些格子拓展,就能模拟出这题了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
const int maxn=1000+5;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;


int n,m,p;
int s[10];

char ma[maxn][maxn];
int ans[10];
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
bool vis[maxn][maxn];
int self[maxn][maxn][10];
queue<pii> que[10];


int main(){
    scanf("%d%d%d",&n,&m,&p);
    for(int i=1;i<=p;i++)scanf("%d",&s[i]);
    memset(self,-1,sizeof(self));
    for(int i=0;i<n;i++){
        scanf("%s",ma[i]);
        for(int j=0;j<m;j++){
            if(ma[i][j]=='.'||ma[i][j]=='#')continue;
            int id=ma[i][j]-'0';
            vis[i][j]=1;
            self[i][j][id]=0;
            ans[id]++;
            que[id].push(mp(i,j));
        }
    }
    int turn=0;
    while(1){
        turn++;
        bool f=0;
        for(int i=1;i<=p;i++){
            int lastp=s[i]*turn;
            while(!que[i].empty()){
                pii cc=que[i].front();
                f=1;
                int cntx=cc.fi,cnty=cc.se;
                if(self[cc.fi][cc.se][i]==lastp)break;
                que[i].pop();
                for(int k=0;k<4;k++){
                    int nx=cntx+dx[k],ny=cnty+dy[k];
                    if(nx<0||ny<0||nx>=n||ny>=m)continue;
                    if(ma[nx][ny]=='#')continue;
                    if(vis[nx][ny])continue;
                    ans[i]++;
                    self[nx][ny][i]=self[cntx][cnty][i]+1;
                    vis[nx][ny]=1;
                    que[i].push(mp(nx,ny));
                }
            }
        }
        if(f==0)break;
    }
    for(int i=1;i<=p;i++)printf("%d ",ans[i]);
    return 0;
}

E. Helping Hiasat
你可以改ID,朋友访问时如果你的ID是不是他的名字他就会不高兴,问有多少个朋友会是高兴的。

注意到每两次改名字之间的朋友之间,这有一个能在这一次不会不高兴。
所以问题转换成求最大独立集了。
用补图跑最大团,抄个模板就行了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
const int maxn=40+5;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;

int n,m;

bool g[maxn][maxn];
int ans;
int mc[maxn];
int lis[maxn][maxn];
int len[maxn];
bool found;
void dfs(int siz){
    int i,j,k;
    if(len[siz]==0){
        if(siz>ans){
            ans=siz;
            found=true;
        }
        return;
    }
    for(k=0;k<len[siz]&&!found;++k){
        if(siz+len[siz]-k<=ans)
            break;
        i=lis[siz][k];
        if(siz+mc[i]<=ans)
            break;
        for(j=k+1,len[siz+1]=0;j<len[siz];++j)
            if(g[i][lis[siz][j]])
                lis[siz+1][len[siz+1]++]=lis[siz][j];
        dfs(siz+1);
    }
}

void max_cluster(){
    int i,j;
    mc[m]=ans=1;
    for(i=m-1;i;--i){
        found=false;
        len[1]=0;
        for(j=i+1;j<=m;++j)
            if(g[i][j])
                lis[1][len[1]++]=j;
        dfs(1);
        mc[i]=ans;
    }
}

map<string,int> ma;
int tot;
string name;
vector<int> vec;
int main(){
    scanf("%d%d",&n,&m);
    for(int i=0,a;i<=n;i++){
        if(i<n)scanf("%d",&a);
        if(a==1||i==n){
            sort(vec.begin(),vec.end());
            vec.erase(unique(vec.begin(),vec.end()),vec.end());
            int siz=vec.size();
            for(int i=0;i<siz;i++){
                int lef=vec[i];
                for(int j=i+1;j<siz;j++){
                    int rig=vec[j];
                    g[lef][rig]=g[rig][lef]=1;
                }
            }
            vec.clear();
        }
        else{
            cin>>name;
            if(ma.find(name)==ma.end()){
                ma[name]=++tot;
            }
            int id=ma[name];
            vec.pb(id);
        }
    }
    for(int i=1;i<=m;i++){
        for(int j=1;j<=m;j++){
            if(i==j)continue;
            g[i][j]=1-g[i][j];
        }
    }
    max_cluster();
    printf("%d\n",ans);
    return 0;
}

#534
D. Game with modulo
交互题,通过问两个数在模意义的大小关系,确定出模数。
还是挺厉害的这一道题目
首先对于i和2i,如果模数a在i和2i之间,那么模意义下i一定大于2i
所以可以倍增i来确定a所在下界
然后在这段区间内,满足前一部分模意义下大于i,后一部分模意义下小于i
第一个模意义下小于i的数就是模数了
还是有些细节的。询问次数也卡的比较死。

这种题目还是需要挖掘性质的,好题。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
const int maxn=1e3+15;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;

int n;

string str;

int main(){
    while(1){
        cin>>str;
        if(str=="end"||str=="mistake")break;
        cout<<"? 0 1"<<endl;
        fflush(stdout);
        cin>>str;
        if(str[0]=='x'){
            cout<<"! 1"<<endl;
            fflush(stdout);
            continue;
        }
        ll lef,rig;
        for(int i=1;i<=1e9;i<<=1){
            cout<<"? "<<i<<" "<<2*i<<endl;
            fflush(stdout);
            cin>>str;
            if(str[0]=='e')exit(0);
            else if(str[0]=='x'){
                lef=i;rig=2*i;break;
            }
        }
        int ret=lef;
        int cc=lef;
        lef++;
        while(lef<=rig){
            ll mid=(lef+rig)/2;
            cout<<"? "<<cc<<" "<<mid<<endl;
            fflush(stdout);
            cin>>str;
            if(str[0]=='e')exit(0);
            else if(str[0]=='x'){
                rig=mid-1;
            }
            else{
                ret=mid;
                lef=mid+1;
            }
        }
        cout<<"! "<<ret+1<<endl;
        fflush(stdout);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值