2022hdu暑期1

 B Dragon slayer

题解

签到题。墙的数量只有15,爆搜或者状压都能比较轻松的通过。

标程

#include<bits/stdc++.h>
using namespace std;

int n,m,K,sx,sy,tx,ty;
struct edge{
	int x[2],y[2]; 
}e[20];

int mp[20][20];

int Lw[20][20],Dw[20][20];

bool dfs(int x,int y){
	mp[x][y]=1;
	if(x==tx && y==ty){
		return 1;
	}
	bool re=0;
	//x-1 y
	if(x>=1 && Lw[x][y]==0 && mp[x-1][y]==0){
		re|=dfs(x-1,y);
	}
	//x+1 y
	if(x+1<n && Lw[x+1][y]==0 && mp[x+1][y]==0){
		re|=dfs(x+1,y);
	}
	//x y-1
	if(y>=1 && Dw[x][y]==0 && mp[x][y-1]==0){
		re|=dfs(x,y-1);
	}
	//x y+1
	if(y+1<m && Dw[x][y+1]==0 && mp[x][y+1]==0){
		re|=dfs(x,y+1);
	}
	return re;
}

bool check(int s){
	memset(mp,0,sizeof(mp));
	memset(Lw,0,sizeof(Lw));
	memset(Dw,0,sizeof(Dw));
	for(int i=0;i<K;++i){
		if((s&(1<<i))==0){
			if(e[i].x[0]==e[i].x[1]){
				for(int j=e[i].y[0];j<e[i].y[1];++j){
					Lw[e[i].x[0]][j]=1;
				}
			}
			else{
				for(int j=e[i].x[0];j<e[i].x[1];++j){
					Dw[j][e[i].y[0]]=1;
				}
			}
		}
	}
	return dfs(sx,sy);
}

int popcount(int x){
	int re=0;
	while(x){
		if(x&1) ++re;
		x>>=1;
	}
	return re;
}

int f[(1<<15)+5];

void solve(){
	cin>>n>>m>>K>>sx>>sy>>tx>>ty;
	for(int i=0;i<K;++i){
		cin>>e[i].x[0]>>e[i].y[0]>>e[i].x[1]>>e[i].y[1];
		if(e[i].x[0]==e[i].x[1]&&e[i].y[0]>e[i].y[1]){
			swap(e[i].y[0],e[i].y[1]);
		}
		if(e[i].y[0]==e[i].y[1]&&e[i].x[0]>e[i].x[1]){
			swap(e[i].x[0],e[i].x[1]);
		}
	}
	int ans=K;
	for(int s=0;s<(1<<K);++s){
		f[s]=0;
	}
	for(int s=0;s<(1<<K);++s){
		if(f[s]){
			continue;
		}
		f[s]=check(s);
		if(f[s]){
			ans=min(ans,popcount(s));
			for(int j=0;j<K;++j){
				f[s|(1<<j)]|=f[s];
			}
		}
	}
	cout<<ans<<endl;
	return;
}

int main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	int t=1;cin>>t;
	for(int i=1;i<=t;++i){
		solve();
	}
	return 0;
} 

C Backpack

题解

fi,j,k表示前i个物品,异或和为j,并且体积为k的方案是否存在。

f_{i,j,k}=f_{i-1,j,k}\vee f_{i-1,j\oplus v_i,k-w_i}

fi,j实际上是fi-1,j和fi-1,j\oplus vi左移wi位后V,可以用bitset压位

标程

#include<bits/stdc++.h>
using namespace std;


int n,m,cnt;

bitset<1050> f[1050],g[1050];


void solve(){
	cin>>n>>m;
	for(int j=0;j<1024;++j){
		f[j].reset();
	}
	f[0][0]=1;
	int x,y;
	int ans=-1;
	for(int i=1;i<=n;++i){
		cin>>x>>y;
		for(int j=0;j<1024;++j){
			g[j]=f[j];
			g[j]<<=x;
		}
		for(int j=0;j<1024;++j){
			f[j]|=g[j^y];
		}
	}
	
	for(int j=0;j<1024;++j){
		if(f[j][m]){
			ans=j;
		}
	}
	cout<<ans<<endl;
	return;
}

int main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	int t=1;cin>>t;
	for(int i=1;i<=t;++i){
		solve();
	}
	return 0;
} 

D Ball

题解

显然我们需要判断出一个数是不是质数,由于范围只有2*10^5 ,各类筛都可以 接下来考虑枚举一下三个点,我们可以分别计算距离并进行判断 但这样子时间复杂度太高,考虑枚举两个点,如何确定第三个点,我们即要求其中一条边小于等于这条边,另一条边大于等于这条边,这可以利用两个bitset的&解决 处理最终答案的时候可以把边从小到大加入避免算重。

标程

#include<bits/stdc++.h>
#define M 2005
using namespace std;
int n,m,cnt,mark[400005];
long long ans;
struct pos{
    int x,y;
}P[M];
struct hzl{
    int s,a,b;
}A[M*M];
bool cmp(hzl a,hzl b){
    return a.s<b.s;
}
bitset<2005>s[M];
int main(){
    mark[1]=1;
    for(int i=2;i<=200000;i++){
        if(mark[i])continue;
        for(int j=i+i;j<=200000;j+=i)mark[j]=1;
    }
    int T;
    scanf("%d",&T);
    while(T--){
        ans=cnt=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)s[i].reset();
        for(int i=1;i<=n;i++)scanf("%d%d",&P[i].x,&P[i].y);
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
                A[++cnt]=(hzl){abs(P[i].x-P[j].x)+abs(P[i].y-P[j].y),i,j};
        sort(A+1,A+cnt+1,cmp);
        for(int i=1;i<=cnt;i++){
            if(!mark[A[i].s])ans+=(s[A[i].a]^s[A[i].b]).count();
            s[A[i].a][A[i].b]=1;
            s[A[i].b][A[i].a]=1;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

F Travel Plan

题解

由于不存在长度为偶数的简单回路,所以任何两个简单回路不存在公共边。 一个不严谨的证明: 如果某两点之间存在三条不重合的简单路径,则三条路径中必然存在相同奇偶性的路径,就会存在偶数 长度的简单回路。 不存在偶数长度的简单回路,说明必然任意两点之间都不存在三条不重合的路径,即任意一条边只会存 在于一个简单回路上。 于是这个图就是仙人掌图。 求最大公因数为x 的路径,可以用莫比乌斯反演转化为求x的倍数的路径。 这样对只需要对n个只包含i的倍数的边的图计算简单路径数量。 仙人掌图上的简单路径数量可以用dp求得。

标程

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back

LL M=998244353;
const int N=1e5+10;

char ss[1<<24],*A=ss,*B=ss;
char gc()
{
  return (A==B&&(B=(A=ss)+fread(ss,1,1<<20,stdin),A==B)?EOF:*A++);
}
int read()
{
	int x=0;
	char c;
	while (c=gc(),c<48||c>57) ; x=c-48;
  while (c=gc(),47<c&&c<58) x=x*10+c-48;
  return x;
}


vector<int> factor[N];

void add(LL &x,LL y){
    x+=y;
    if(x>=M) x-=M;
}

bool is_pri[N+10];
LL pri[60000];
int mu[N+10];
int cntp=0;

void init_pri(){
    mu[1]=1;
    for(int i=2;i<=N;++i){
        if(!is_pri[i]) {
            pri[++cntp]=i;
            mu[i]=-1;
        }
        for(int j=1;j<=cntp&&pri[j]*i<=N;++j){
            is_pri[pri[j]*i]=1;
            if(i%pri[j]==0) {
                mu[pri[j]*i]=0;
                break;
            }
            else{
                mu[pri[j]*i]=-mu[i];
            }
        }
    }
}


void init(){
    for(int i=1;i<=100000;++i) factor[i].clear();
    for(int i=1;i<=100000;++i){
        for(int j=i;j<=100000;j+=i){
            factor[j].pb(i);
        }
    }
    init_pri();
}

int n,m,K;
int num,tp,cnt;
struct edge{
    int u,v;
};
bool Flag;
int Sum;
vector<edge> U[N];
vector<int> a[N],b[N+N];
int dfn[N],low[N],q[N],cf[N];

void Tarjan(int x,int fa){
    int y;
    dfn[x]=low[x]=++num;cf[x]=0;
    q[++tp]=x;
    for(int i=0;i<a[x].size();++i){
        y=a[x][i];
        if(!dfn[y]){
            Tarjan(y,x);
            cf[x]+=cf[y];
            low[x]=min(low[x],low[y]);
            if(low[y]==dfn[x]){
                ++cnt;b[cnt].clear();
                for(int j=0;j!=y;){
                    b[cnt].push_back(q[tp]);
                    b[q[tp]].push_back(cnt);
                    j=q[tp];--tp;
                }
                b[cnt].push_back(x);
                b[x].push_back(cnt);
            //    cout<<cnt<<endl;
            //    for(int j=0;j<b[cnt].size();++j) cout<<b[cnt][j].r<<" ";
            //    cout<<endl;
            }
        }
        else if(dfn[y]<dfn[fa]){
            low[x]=min(low[x],dfn[y]);
            cf[x]++;
            cf[y]--;
        }
        else{
            low[x]=min(low[x],dfn[y]);
        }
    }
    if(cf[x]>1) Flag=1;
    return;
}

LL F[N+N];
LL ans[N];

void DP(int x,int fa,int op){
    int y,z,l=b[x].size();
    for(int i=0;i<l;++i){
        y=b[x][i];
        if(y==fa) continue;
        DP(y,x,op);
    }
    
    if(x<=n){
        F[x]=1;
        for(int i=0;i<l;++i){
            y=b[x][i];
            if(y==fa) continue;
            add(ans[op],F[y]*F[x]%M);
            add(F[x],F[y]);
        }
    }
    else if(l==2){
        F[x]=0;
        for(int i=0;i<l;++i){
            y=b[x][i];
            if(y==fa) continue;
            add(F[x],F[y]);
        }
    }
    else{
        F[x]=0;
        for(int i=0;i<l;++i){
            y=b[x][i];
            if(y==fa) continue;
            add(ans[op],F[y]*F[x]%M);
            add(F[x],(F[y]+F[y])%M);
        }
    }
    return;
}
void solve(){
    int u,v,w;
    n=read();m=read();K=read();
    for(int i=1;i<=K;++i){
        U[i].clear();
        ans[i]=0;
    }
    
    for(int i=1;i<=m;++i){
        u=read();v=read();w=read();
        for(auto j:factor[w]){
            U[j].pb((edge){u,v});
        }
    }
    vector<int> que;
    for(int i=1;i<=K;++i){
        que.clear();
        for(auto ed:U[i]){
            a[ed.u].clear();
            a[ed.v].clear();
            b[ed.u].clear();
            b[ed.v].clear();
            dfn[ed.u]=dfn[ed.v]=0; 
            que.pb(ed.u);
            que.pb(ed.v);
        }
        for(auto ed:U[i]){
            a[ed.u].pb(ed.v);
            a[ed.v].pb(ed.u);
        }
        num=tp=0;cnt=n;
        for(auto x:que){
            if(!dfn[x]){
                Tarjan(x,0);
                if(Flag){
                    cout<<"wrong data"<<endl;
                    exit(0);
                    return;
                }
                DP(x,0,i);
            } 
        }
    }
    for(int i=1;i<=K;++i){
        for(int j=2;j*i<=K;++j){
            ans[i]+=mu[j]*ans[i*j];
        }
        ans[i]=(ans[i]%M+M)%M;
    }
//    for(int i=1;i<=K;++i){
//        cout<<ans[i]<<" ";
//    }
//    cout<<endl;

    LL Ans=0;
    for(int i=1;i<=K;++i){
        Ans^=ans[i];
    }
    cout<<Ans<<endl;
    return;
}

int main(){
    
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    
    init();
    
    
    int t=1;
//	cin>>t;
	t=read();
    for(int i=1;i<=t;++i){
        solve();
    }
    return 0;
} 

K Random

题解

答案为(n-m)/2,求出2的逆元即可

标程

#include <bits/stdc++.h>
using namespace std;
const int mo=1e9+7;
int main()
{
	ios::sync_with_stdio(false);
	int gg=(mo+1)/2;
	int T;
	cin>>T;
	while (T--)
	{
		int n,m;
		cin>>n>>m;
		cout<<1ll*(n-m)*gg%mo<<endl;
	}
	return 0;
}

L Alice and Bob

题解

将每个值为i的数字视为2^(n-i),那么Alice的胜利条件就是最终局面中能出现2^n。 Alice将数字分成两个集合,Bob将其中一个集合减一,就相当于将这个集合中的数全部乘2,然后将另一 个集合删去。 如果Alice能将集合中的数字按照值二等分,那么无论Bob怎么操作,黑板上所有数字的总和实际是不变 的。 如果集合中的数字总和超过2^n,由于所有数字都是不超过2^n的2的幂次,那么Alice的每次分割总能使得两边集合的值均不小于2^(n-1)。 因此直接判断所有数字的2的幂次的总和即可。

标程

#include<bits/stdc++.h>
using namespace std;

int n;
int a[1000005];



void solve(){
	cin>>n;
	for(int i=0;i<=n;++i){
		cin>>a[i];
	}
	for(int i=n;i>0;--i){
		a[i-1]+=a[i]/2;
	}
	if(a[0]) cout<<"Alice\n";
	else cout<<"Bob\n";
}

int main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	int t=1;cin>>t;
	for(int i=1;i<=t;++i){
		solve();
	}
	return 0;
} 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值