2019 Multi-University Training Contest 5

题目链接:http://acm.hdu.edu.cn/search.php?field=problem&key=2019+Multi-University+Training+Contest+5&source=1&searchmode=source

three arrays(字典树+贪心)

HDU - 6625
参考:https://blog.youkuaiyun.com/mmk27_word/article/details/98611040
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int maxn=100010*30;
const int N=100010;

int tri[2][maxn][2];
int num[2][maxn],pos[2];
void insert1(int cur,int op)
{
	int c=0,x;
	for(int i=29;i>=0;i--){
		if((1<<i)&cur) x=1;
		else x=0;
		if(tri[op][c][x]==0){
			tri[op][c][x]=++pos[op];
//			tri[op][c+1][0]=tri[op][c+1][1]=num[op][c+1]=0;
			tri[op][pos[op]][0]=tri[op][pos[op]][1]=num[op][pos[op]]=0;
		}
		c=tri[op][c][x];
		num[op][c]++;
	}
}
int query()
{
	int c0=0,c1=0;
	int ans=0;
	for(int i=29;i>=0;i--){
		if(num[0][tri[0][c0][0]]&&num[1][tri[1][c1][0]]){
			c0=tri[0][c0][0];c1=tri[1][c1][0];
			num[0][c0]--;num[1][c1]--;
			
		}else if(num[0][tri[0][c0][1]]&&num[1][tri[1][c1][1]]){
			c0=tri[0][c0][1];c1=tri[1][c1][1];
			num[0][c0]--;num[1][c1]--;
			
		}else if(num[0][tri[0][c0][0]]&&num[1][tri[1][c1][1]]){
			c0=tri[0][c0][0];c1=tri[1][c1][1];
			num[0][c0]--;num[1][c1]--;
			ans+=1<<i;
		}else{
			c0=tri[0][c0][1];c1=tri[1][c1][0];
			num[0][c0]--;num[1][c1]--;
			ans+=1<<i;
		}
	}
	return ans;
}
int c[N],n;
int main()
{
	int t;scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		int x;
		pos[0]=pos[1]=0;
		tri[0][0][0]=tri[0][0][1]=num[0][0]=0;
		tri[1][0][0]=tri[1][0][1]=num[1][0]=0;
		for(int i=1;i<=n;i++){
			scanf("%d",&x);insert1(x,0);
		}
		for(int i=1;i<=n;i++){
			scanf("%d",&x);insert1(x,1);
		}
		for(int i=1;i<=n;i++){
			c[i]=query();
		}
		sort(c+1,c+n+1);
		for(int i=1;i<=n;i++){
			printf("%d%c",c[i],i==n?'\n':' ');
		}
	}
	return 0;
}

equation(分段函数/枚举)

HDU - 6627
题解&代码:https://blog.youkuaiyun.com/songziqi98/article/details/98736140
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
const int SIZE = 1e5+5;
const int INF = 0x3f3f3f3f;
struct Node {
    int a, b;
    int id;
    double aDb;
    Node() : a(0), b(0) {}
} arr[SIZE];
int xNum, num;
bool cmp(const Node& a, const Node& b) {
    if(a.aDb != b.aDb) return a.aDb < b.aDb;
    else return a.id < b.id;
}
struct A {
    int a, b;
    int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
    void get() {
        int num = gcd(a, b);
        a /= num;
        b /= num;
    }
    inline bool operator < (const A &tt) const {
        double t1 = (double)a/b;
        double t2 = (double)tt.a/tt.b;
        return t1 < t2;
    }
};
set<A> ans;
double l, r;
int main() {
    // freopen("RAW/in", "r", stdin);
    // freopen("RAW/out", "w", stdout);
    int T;
    scanf("%d", &T);
    while(T--) {
        ans.clear();
        l = r = -INF;//当前区间 
        int n, c;
        xNum = num = 0;
        scanf("%d%d", &n, &c);
        for(int i = 0; i < n; i++) {
            scanf("%d%d", &arr[i].a, &arr[i].b);
            arr[i].id = i;
            xNum += (-arr[i].a);
            num += (-arr[i].b);
            arr[i].aDb = -((double)arr[i].b/arr[i].a);//求出分界点 
        }
        sort(arr, arr + n, cmp);
        bool flag = false;
        for(int i = 0; i <= n; i++) {
            if(i < n) r = arr[i].aDb;
            else r = INF;
            int a = c-num;
            if(xNum == 0 && a == 0) {//无穷解 
                flag = true;
                break;
            }
            A temp;
            if(a == 0) {//零解 
                temp.a = 0;
                temp.b = 1;
                if(0 >= l && 0 <= r) ans.insert(temp); 
            } else if(xNum != 0){//一般解 
                double tt = (double)a/xNum;
                if(tt >= l && tt <= r) {
                    temp.a = a;
                    temp.b = xNum;
                    temp.get();
                    ans.insert(temp);
                }
            }//更新 num xNum 
            num += 2*arr[i].b;
            xNum += 2*arr[i].a;
            l = arr[i].aDb;
        }
        if(flag) printf("-1");
        else {
            int len = ans.size();
            printf("%d", len);
            for(set<A>::iterator it = ans.begin(); it != ans.end(); it++) {
                if(1.0*(*it).a/(*it).b < 0) printf(" -");
                else printf(" ");
                printf("%d/%d", abs((*it).a), abs((*it).b));
            }
        }
        printf("\n");
    }
    return 0;
}

permutation 1(思维/排列/搜索)

HDU - 6628
代码:https://blog.youkuaiyun.com/tianwei0822/article/details/98613084
题意:给定n和k,对于n的所有排列,求出字典序第k小的作差序列对应的排列。
对于1 2 4 3作差序列就是1 2 -1
题解:由于n只有20,k只有1e4,那么因为7!<1e4,8!>1e4,所以对于n-2>=8的情况,我们只需考虑固定n,1开头,剩余数做字典序第k小就是原题所求。对于n-2<8的情况,我们暴力处理下即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
int n,m,t;
struct p{
    int num[11];
    char str[11];
}a[11][N];
 
bool cmp(p aa, p bb){
    return strcmp(aa.str,bb.str)<0;
}
 
int main(){
    int b[15]={0,1,2};
    for(int k=2;k<=9;k++){
        int cnt=1;
        do{
            for(int i=1;i<=k;i++){
                a[k][cnt].num[i]=b[i];
                if(i!=1)a[k][cnt].str[i-2]=b[i]-b[i-1]+'A';
            }
            a[k][cnt].str[k-1]='\0';
            cnt++;
        }while(next_permutation(b+1,b+k+1));
        sort(a[k]+1,a[k]+cnt,cmp);
        b[k+1]=k+1;
    }
    scanf("%d",&t);
    while(t--){
        int k;
        scanf("%d%d",&n,&k);
        if(n>9){
            int c[30];
            c[1]=n;
            for(int i=2;i<=n;i++)c[i]=i-1;
            for(int i=1;i<k;i++)
                next_permutation(c+1,c+n+1);
            printf("%d",c[1]);
            for(int i=2;i<=n;i++)
                printf(" %d",c[i]);
            printf("\n");
            continue;
        }
        printf("%d",a[n][k].num[1]);
        for(int i=2;i<=n;i++)
            printf(" %d",a[n][k].num[i]);
        printf("\n");
    }
    return 0;
}

直接dfs也行:https://blog.youkuaiyun.com/qq_40655981/article/details/98591885
思路:直接dfs枚举差异序列从小往大搜,然后对不合法的情况去掉(差异序列中元素的最大-最小<n-1才合法,重复的也不合法)
代码

#include<bits/stdc++.h>

#define LL long long
#define fi first
#define se second
#define mp make_pair
#define pb push_back

using namespace std;

LL gcd(LL a,LL b){return b?gcd(b,a%b):a;}
LL lcm(LL a,LL b){return a/gcd(a,b)*b;}
LL powmod(LL a,LL b,LL MOD){LL ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;}
const int N = 503;
int t,n,k;
int vis[N],p[N];
bool dfs(int now,int pre,int l,int r){
	if(now==n){
		if(k==1){
			for(int i=0;i<n;i++){
				cout<<p[i]-l+1;
				if(i<n-1)cout<<' ';
				else cout<<'\n';
			}
			return 1;
		}
		k--;
		return 0;
	}
	for(int i=1-n;i<=n-1;i++){//枚举差异序列字典序最小
		if(!vis[i+pre]){
			vis[i+pre]=1;
			if(max(i+pre,r)-min(l,i+pre)<=n-1){
				p[now]=i+pre;
				if(dfs(now+1,i+pre,min(i+pre,l),max(i+pre,r))){
					vis[i+pre]=0;
					return 1;
				}
			}
			vis[i+pre]=0;
		}
	}
	return 0;
}
int main(){
	ios::sync_with_stdio(false);
	for(cin>>t;t;t--){
		cin>>n>>k;int sta=0;
		vis[n]=1;
		p[0]=n;
		dfs(1,n,n,n);//相对大小
		vis[n]=0;
	}	
	return 0;
}



string matching(扩展KMP)

HDU 6629
基本题意就大概是求s的所有后缀子串和s的最长匹配前缀串长度之和。

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

int const maxn=1000100;
//扩展kmp:求t每一个后缀字符串匹配s最长前缀长度
/*
extend[i]:S[i]...S[n-1]与 T 的最长相同前缀的长度
next[i]: T[i]...T[m - 1]与 T 的最长相同前缀长度;
*/
int lent,nex[maxn];
char t[maxn];
long long ans;
void getnext(){
    lent=strlen(t);
    int a=0,p=0;//p是最长的匹配到的位置,a是它开始匹的位置
    nex[0]=lent;
    for(int i=1;i<lent;i++){
        if(i>=p||i+nex[i-a]>=p){
            if(i>=p)p=i;
            while(p<lent&&t[p]==t[p-i])p++;
            nex[i]=p-i;a=i;
        }
        else nex[i]=nex[i-a];
        if(i+nex[i]==lent)ans+=nex[i];
        else ans+=nex[i]+1;
    }
}
int main(){
    int Y;
    scanf("%d",&Y);
    while(Y--){
        scanf("%s",t);
        ans=0;
        getnext();
        cout<<ans<<endl;
    }
    return 0;
}

permutation 2(思维/递推)

HDU - 6630
题意:给定义一个x,y求以x为第一元素,y为最后一个元素,且任意相邻元素差值绝对值不大于2的排列个数
题解:转化理解,有n个点,起点为x,终点为y,每一步只能跳1格和2格,每个点都要访问且访问一次,求所有走法。这里我们假设x<y,x>y的情况是类似的,由于要走完所有的点,对于x左边的点,我们要确保全部走完,且能返回到x右边来,那么走法唯一,即从x,x-2,x-4到1/2,再返回走,最后回到x+1;对于y右边的点,由于y要最后访问,需要把y右边的点,全部访问后再回到y,其起点是y-1;那么问题就变成了求[x+1,y-1]的走法了,递推即可。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int  maxn=100010;
const int mod=998244353;

ll a[maxn];
int n;
void init()
{
	a[1]=a[2]=a[3]=1;
	for(int i=4;i<maxn;i++){
		a[i]=(a[i-1]+a[i-3])%mod;
	}
}
int main()
{
	init();
	int t;scanf("%d",&t);
	int x,y;
	while(t--){
		scanf("%d%d%d",&n,&x,&y);
		if(x>y) swap(x,y);
		if(y==x+1){
			if(x==1||y==n) printf("1\n");
			else printf("0\n");
			continue;//
		}
		if(x!=1) x++;
		if(y!=n) y--;
		int cur=y-x+1;
		printf("%lld\n",a[cur]);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值