2018 Multi-University Training Contest 3

 

hdu 6322  Problem D. Euler Function

定义一类数,该类数的欧拉函数都是合数,需要求第k大的该类数

打表发现 5 7 8 9 10 11 12 13 。。。。。所以第1大为5 特判一下,之后都是连续的。

#include<bits/stdc++.h>
using namespace std;
long long  dp[100010];
vector<int>p[100010];
void dfs(int x,int pre)
{
    dp[x]=dp[pre]+1;
    for(int i=0;i<p[x].size();i++)
    {
        if(p[x][i]!=pre)
        {
            dfs(p[x][i],x);
        }
    }
}
long long qpow(long long x,long long n,long long mod)
{
    long long ans=1;
    while(n)
    {
        if(n&1)ans=ans*x%mod;
        x=x*x%mod;
        n>>=1;
    }
    return ans;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        if(n==1)
        {
            printf("5\n");
        }
        else{
            printf("%d\n",n+5);
        }
    }
    return 0;
}

 

hdu 6324 grab the tree

给出一个数,a可以拿走任意一些点,但这些点之间不能存在直接连接的边,另一个人拿剩下的所有点,最后2个人比较自己拿到的点的异或和谁大。

如果所有的数异或和为0,那么假设a拿走的点的异或和为k,那么我们明显能得到另外一个人的异或和必定也为k。所以平局

如果不为0,那么所有的数的异或和的最高位的1一定是由奇数个该位为1的数得到,那么第一个人只要拿1个该最高位为1的数,那么剩下的数的异或和的该最高位则会因为有偶数个1异或而得0,无论如何都不会比第一个人的那个数大。

所以第一个人必胜

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        scanf("%d",&n);
        int a;
        scanf("%d",&a);
        int b;
        for(int i=1;i<n;i++)
        {
            scanf("%d",&b);
            a=a^b;
        }
        int u,v;
        for(int i=1;i<=n-1;i++)
        {
            scanf("%d%d",&u,&v);
        }
        if(a>0)
        printf("Q\n");
        else printf("D\n");
    }
    return 0;
}

 

hdu 6330 Problem L. Visual Cube

找规律。。。。不算太麻烦的模拟⑧

#include<bits/stdc++.h>
using namespace std;
char ma[88][88];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int a,b,c;
        cin>>a>>b>>c;
        for(int i=1;i<=c*2+b*2+1;i++)
        {
            for(int j=1;j<=a*2+b*2+1;j++)
            ma[i][j]='.';
        }
        for(int i=b*2+1;i<=2*b+1+2*c;i+=2)
        {
            bool f=1;
            for(int j=1;j<=2*a+1;j++)
            {
                if(f)ma[i][j]='+';
                else ma[i][j]='-';
                f=!f;
            }
        }
        for(int i=b*2+2;i<=2*b+1+2*c;i+=2)
        {
            bool f=1;
            for(int j=1;j<=2*a+1;j++)
            {
                if(f)ma[i][j]='|';
                else ma[i][j]='.';
                f=!f;
            }
        }
        for(int i=1;i<=b*2;i+=2)
        {
            bool f=1;
            for(int j=b*2-i+2;j<=a*2+b*2+1-i+1;j++)
            {
                if(f)
                ma[i][j]='+';
                else ma[i][j]='-';
                f=!f;
            }
        }
        for(int i=2;i<=b*2;i+=2)
        {
            bool f=1;
            for(int j=b*2-i+2;j<=a*2+b*2+1-i+1;j++)
            {
                if(f)
                ma[i][j]='/';
                else ma[i][j]='.';
                f=!f;
            }
        }
        for(int i=1;i<=2*b;i+=2)
        {
            bool f=1;
            for(int j=b*2+2-i;j<=2*b+2*c+1-i;j++)
            {
                if(f)
                ma[j][i+2*a+1]='.';
                else ma[j][i+2*a+1]='/';
                f=!f;
            }
        }
        for(int i=2;i<=2*b;i+=2)
        {
            bool f=1;
            for(int j=b*2+2-i;j<=2*b+2*c+1-i;j++)
            {
                if(f)
                ma[j][i+2*a+1]='|';
                else ma[j][i+2*a+1]='+';
                f=!f;
            }
        }
        for(int i=1;i<=c*2+b*2+1;i++)
        {
            for(int j=1;j<=a*2+b*2+1;j++)
            cout<<ma[i][j];
            cout<<endl;
        }
    }
    return 0;
}

 

hdu 6319 Problem A. Ascending Rating

单调队列倒着搞一遍,维护一个单调递减队列即可。

每次遍历到一个i,把队尾那些位置超过了i+m-1的数字推掉,再在队头把<=a[i]的数字也推掉,再把a[i]压进队头。

最后队尾为最大值,队列的size为count  。

比赛的时候太菜不会单调队列。现在会了

#include<bits/stdc++.h>
using namespace std;
struct node{
	long long da;
	long long wz;
}a[11111111];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        long long n,m,k,p,q,r,mod;
        scanf("%lld%lld%lld%lld%lld%lld%lld",&n,&m,&k,&p,&q,&r,&mod);
        deque<node>qq;
        for(int i=1;i<=k;i++)
        {
            scanf("%lld",&a[i].da);
            a[i].wz=i;
        }
        for(int i=k+1;i<=n;i++)
        {
            a[i].da=(p*a[i-1].da+q*i+r)%mod;
            a[i].wz=i;
        }
        for(int i=n;i>n-m+1;i--)
        {
        	if(qq.empty())
        	{
        		qq.push_back(a[i]);
			}
			else{
				while(!qq.empty()&&qq.front().da<a[i].da)
				{
					qq.pop_front();
				}
				qq.push_front(a[i]);
			}
		}
		long long ana=0;
		long long anb=0;
        for(int i=n-m+1;i>=1;i--)
        {
        	while(!qq.empty()&&qq.back().wz>i+m-1)
        	{
        		qq.pop_back();
			}
			while(!qq.empty()&&qq.front().da<=a[i].da)
			{
				qq.pop_front();
			}
			qq.push_front(a[i]);
		    ana+=qq.back().da^i;
		    anb+=qq.size()^i;
		}
        printf("%lld %lld\n",ana,anb);
    }
    return 0;
}

。。。印象深刻

 

hdu 6321 Problem C. Dynamic Graph Matching

一道状压dp题。

先解释一下matching ,k=4 则需要挑出4条边,且这四条边无重合点,也就是说这4条边需要8个不同的点来表示。

因为n=10 ,那么我们可以用0~1023来表示我们选了哪些边(在这题我们只需要记录边的数量也就是二进制里1的数量即可不需要记录选了哪些边)   dp[i]表示i这个二进制里我们选了数位为1的这些点的答案数。

每次加入一条边 a,b  那么如果某个i的二进制 a--和b--对应位置都为1,那么也就是说这个状态可以由i-(1<<a)-(1<<b)的状态得到,那么就要加上i-(1<<a)-(1<<b)的答案数。以此来累加。

减去一条边,那么我们就反过来减掉即可。

ans[i]表示,选了i个点的答案数,是为了方便输出。题目要求从1~n/2条边,那么对应到点的数量上就是 2 4 6 。。。n-n%2这些下标对应的ans数组的数值。

+1:发现有的人代码能跑2000+ms   我这个码跑了3000+ms   ,因为如果i的1的数量为奇数是不需要去更新的。。。

#include<bits/stdc++.h>
using namespace std;
long long dp[1025];
long long ans[1025];
long long cnt[1025];
long long mod=1e9+7;
int main(){
	int t;
	cin>>t;
	for(int i=1;i<=1023;i++)
	{
		int lss=i;
		int js=0;
		while(lss)
		{
			if(lss%2==1)
			js++;
			lss/=2;
		}
		cnt[i]=js;
	}
	while(t--)
	{
		int n,m;
		cin>>n>>m;
		memset(dp,0,sizeof(dp));
		memset(ans,0,sizeof(ans));
		char op[11];
		dp[0]=1;
		int a,b;
		while(m--)
		{
			scanf("%s%d%d",&op,&a,&b);
			a--;
			b--;
			if(op[0]=='+')
			{
				for(int i=1;i<(1<<n);i++)
				{
					if(i&(1<<a)&&i&(1<<b))
					{
						dp[i]=(dp[i]+dp[i-(1<<a)-(1<<b)])%mod;
						ans[cnt[i]]=(ans[cnt[i]]+dp[i-(1<<a)-(1<<b)])%mod;
					}
				}
			}
			else{
				for(int i=1;i<(1<<n);i++)
				{
					if(i&(1<<a)&&i&(1<<b))
					{
						dp[i]=(dp[i]-dp[i-(1<<a)-(1<<b)]+mod)%mod;
						ans[cnt[i]]=(ans[cnt[i]]-dp[i-(1<<a)-(1<<b)]+mod)%mod;
					}
				}
			}
			int q=0;
			for(int i=2;i<=n;i+=2)
			{
				if(q++)printf(" ");
				printf("%lld",ans[i]);
			}
			printf("\n");
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值