HGOI10.28集训题解

题解

今天这个题没一个正常的
早上睡过头了,起来肝还痛着


第一题——Jingle

【题目描述】

  • 给出若干字符W/H/Q/E/S/T/X分别代表节拍大小1、1/2、1/4、1/8、1/16、1/32、1/64,用/分割为单元,求有多少个单位的节拍刚好为1。

  • 水题,不讲!
#include <bits/stdc++.h>
using namespace std;
inline void fff(){
	freopen("jingle.in","r",stdin);
	freopen("jingle.out","w",stdout);
}
inline int read(){
	int x=0,m=1;char ch=getchar();
	while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
	if(ch=='-') m=-1,ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return m*x;
}
const int N=1e6+10;
int val[200];
char ch[N];
int n;
int main(){
//	fff();
	cin>>ch;
	n=strlen(ch);
	ch[n++]='/';
	val['W']=64,val['H']=32,val['Q']=16;
	val['E']=8,val['S']=4,val['T']=2,val['X']=1;
	int sum=0,ans=0;
	for(int i=0;i<n;i++){
		if(ch[i]=='/'){
			if(sum==64) ans++;
			sum=0;
		}else sum+=val[ch[i]];
	}
	cout<<ans;
}

第二题——Perfect

【题目描述】

  • 给定M个二元组 ( A i , B i ) (A_i, B_i) (Ai,Bi),求 X 1 X_1 X1, …, X N X_N XN满足:对于任意 ( A i , B i ) (A_i, B_i) (Ai,Bi),有 ∣ X A i − X B i ∣ = 1 |X_{A_i} - X_{B_i}| = 1 XAiXBi=1成立。
  • 有解输出YES和合法解,没有输出NO

  • 这道题我刚开始还没想出来
  • 其实你会发现好像两个点相邻的只有相差为1,那么数值就只有1和0两个解了。然后就发现这个是二分图
  • 但其实不需要当二分图做。数值是唯一的就当差分约束就可以了。

#include <bits/stdc++.h>
using namespace std;
inline void fff(){
	freopen("perfect.in","r",stdin);
	freopen("perfect.out","w",stdout);
}
inline int read(){
	int x=0,m=1;char ch=getchar();
	while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
	if(ch=='-') m=-1,ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return m*x;
}
const int N=10010;
const int M=110000;
const int INF=0x3f3f3f;
int n,m;
struct node{
	int x,y;
}a[M];
int ans[N];
int main(){
//	fff();
	n=read(),m=read();
	for(int i=1;i<=m;i++){
		int u,v;
		u=read(),v=read();
		a[i].x=u,a[i].y=v;
	}
	memset(ans,-1,sizeof(ans));
	for(int i=1;i<=m;i++){
		int u=a[i].x,v=a[i].y;
		if((ans[u]==-1)&&(ans[v]!=-1)) swap(u,v);
		if(ans[u]==-1){
			ans[u]=0;
			ans[v]=ans[u]+1;
		}else if(ans[v]==-1){
			ans[v]=1-ans[u];
		}else if(ans[u]!=1-ans[v]){
			printf("NO");
			return 0;
		}
	}
	printf("YES\n");
	for(int i=1;i<=n;i++) printf("%d ",ans[i]);
	return 0;

}

第三题——Pair

【题目描述】

  • 给出 N ∗ M N*M NM的图,包含X和1-9的数字,分别表示墙和动物。相同的能够联通的动物可以匹配然后消失,消失之后留下空格能够给别的动物做路径。现在要求出最大匹配数的情况下最小的路径长度。

  • 这道题其实蛮骚的。就是纯的暴力,第一遍bfs搜状态,套一个bfs搜匹配。
  • 然后我就T了一发
  • 直接上代码吧。这种题没什么好优化的其实。

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=2147483647;
const int mo=1000000007;
const int N=7;
using namespace std;
int c[11][37][2],a[N][N],ans,n,m,ans1;
short int hashh[33554532][2];
int zz[4][2]=
{
 {0,1},
 {1,0},
 {0,-1},
 {-1,0}
};
inline int dg1(int b[N][N],int x,int y,int v,int dis[N][N])
{
    for(int i=0;i<=3;i++)
    {
        int xx=zz[i][0]+x,yy=zz[i][1]+y;
        if(xx<1 || xx>n || yy<1 || yy>m) continue;
        if(b[xx][yy]==11)
        {
            if(dis[xx][yy]>dis[x][y]+1) dis[xx][yy]=dis[x][y]+1,dg1(b,xx,yy,v,dis);
        }
        else
        if(b[xx][yy]==v)
        {
            dis[xx][yy]=min(dis[x][y]+1,dis[xx][yy]);
        }
    }
}
inline int dg(int b[N][N],int v,int sum)
{
    int num=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(b[i][j] && b[i][j]!=11) num+=1<<((i-1)*m+j-1);
        }
    if(!hashh[num][0])
    {
        hashh[num][0]=sum;
        hashh[num][1]=v;
    }
    else
    {
        if(hashh[num][0]>sum) return 0;
        if(hashh[num][0]==sum && hashh[num][1]<=v) return 0;
        hashh[num][0]=sum;
        hashh[num][1]=v;
    }
    bool q=true;
    int dis[N][N],mn;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(b[i][j] && b[i][j]!=11)
            {
                memset(dis,43,sizeof(dis));
                dis[i][j]=0;
                dg1(b,i,j,b[i][j],dis);
                int g=b[i][j];
                mn=maxlongint;
                for(int k=1;k<=c[g][0][0]-1;k++)
                    for(int l=k+1;l<=c[g][0][0];l++)
                    {
                        if(dis[c[g][k][0]][c[g][k][1]]>dis[c[g][l][0]][c[g][l][1]])
                        {
                            int o=c[g][k][0];
                            c[g][k][0]=c[g][l][0];
                            c[g][l][0]=o;
                            o=c[g][k][1];
                            c[g][k][1]=c[g][l][1];
                            c[g][l][1]=o;
                        }
                    }
                for(int k=1;k<=c[g][0][0];k++)
                    if(dis[c[g][k][0]][c[g][k][1]]!=dis[0][0] && b[c[g][k][0]][c[g][k][1]]==b[i][j] && (i!=c[g][k][0] || j!=c[g][k][1]))
                    {
                        b[i][j]=b[c[g][k][0]][c[g][k][1]]=11;
                        dg(b,v+dis[c[g][k][0]][c[g][k][1]]-1,sum+1);
                        q=false;
                        b[i][j]=b[c[g][k][0]][c[g][k][1]]=g;
                    }
            }
        }
    if(q)
    {
        if(sum>ans)
        {
            ans=sum;
            ans1=v;
        }
        else
        if(sum==ans && ans1>v) ans1=v;
        return 0;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            char ch=getchar();
            while((ch<'0' || ch>'9') && ch!='X') ch=getchar();
            if(ch>='0' && ch<='9')
            {
                a[i][j]=ch-47;
                c[ch-47][0][0]++;
                c[ch-47][c[ch-47][0][0]][0]=i;
                c[ch-47][c[ch-47][0][0]][1]=j;
            }
        }
    ans=0;
    ans1=maxlongint;
    dg(a,0,0);
    printf("%d %d",ans,ans1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值