20190731杭电多校第四场

1001 AND Minimum Spanning Tree(Solved By jlz/cys)

贪心。

对于每个数,找二进制形式下末尾连续1的数量,若为i,则可连到数字2^(i-1),若2^(i-1)不存在,则连到1最优。

AC代码:

using namespace std;
#include<bits/stdc++.h>
int t,n,i,x;
int a[200001];
long long sum,ans;
int main()
{
    scanf("%d",&t);
    while (t!=0)
    {
        t--;
        scanf("%d",&n);
        for (i=2;i<=n;i++)
        {
            sum=1;
            x=i;
            while (x!=0)
            {
                if (x%2==0)
                  break;
                else
                {
                    sum=sum*2;
                    x=x/2;
                }
            }
            if (sum>n)
              a[i]=1;
            else
              a[i]=sum;
        }
        ans=0;
        for (i=2;i<=n;i++)
          ans+=a[i]&i;
        printf("%lld\n",ans);
        for (i=2;i<=n;i++)
          if (i!=n)
            printf("%d ",a[i]);
          else
            printf("%d\n",a[i]);
    }
    return 0;
}

1002 Colored Tree(待补)

1003 Divide the Stones(Solved By cys/jlz)

题面很坑的少了n/k,导致最后才知道还得保证每组是n/k个石头。

显然无解的情况:

1、\frac{n*(n+1)}{2}\%k!=0,即总和不为k的倍数,从而不可能分为k组和相等的石头;

2、n==k且n!=1。

因为要分成k组,每组n/k个石头。

将n个石头等分为n/k个区间,每个区间都是连续k个值。

若n/k为偶数,则可每两个区间凑在一起,保持k组的差值始终为0即可。

若n/k为奇数,则k必为奇数,否则就会是显然无解的情况1。(n/k-3)是偶数,先两两之间就可以凑出为0的情况即可。然后考虑用剩下三个区间凑出相等的k组。

三个区间凑的情况可以试试数据15 5

然后就可以发现一种简单的构造方法,第一列从大到小,第二列按间隔为2的形式从小往大取(其实就是分奇偶),这样可以保证最后一列要取的数字不会重复,最后一列直接用单组区间和减去已经取了的区间和即可。 

AC代码:

using namespace std;
#include<bits/stdc++.h>
int t,x,i,j;
long long n,k; 
vector<int> a[100001];
long long sum[100005];
int main()
{
//	freopen("in.txt","r",stdin);
	scanf("%d",&t);
	while (t)
	{
		t--;
		scanf("%lld%lld",&n,&k);
		if (n==1)
		{
			printf("yes\n1\n");
			continue;
		}
		if ((n*(n+1)/2)%k!=0 || n==k)
		{
			printf("no\n");
			continue;
		}
		printf("yes\n");
		for (i=1;i<=k;i++)
		  a[i].clear();
		x=n/k;
		if (x%2==0)
		{
			for (i=1;i<=x;i++)
			{
				for (j=1;j<=k;j++)
				  if (i%2==1)
				    a[j].push_back((i-1)*k+j);
				  else
				    a[j].push_back((i-1)*k+(k-j+1));
			}
		}
		else
		{
			for (i=1;i<=x-3;i++)
			{
				for (j=1;j<=k;j++)
				  if (i%2==1)
				    a[j].push_back((i-1)*k+j);
				  else
				    a[j].push_back((i-1)*k+(k-j+1));
			}
			//最后三列 
			for(int i=1;i<=k;i++) sum[i]=0;
			for(int j=1;j<=k;j++) a[j].push_back((x-3)*k+k-j+1);
			for(int j=1,z=(x-2)*k+1;z<=(x-1)*k;j++,z+=2) a[j].push_back(z);
			for(int j=k/2+2,z=(x-2)*k+2;j<=k;j++,z+=2) a[j].push_back(z);
			for(int i=0;i<=x-2;i++) for(int j=1;j<=k;j++) sum[j]+=a[j][i];
			for(int j=1;j<=k;j++){
				a[j].push_back(n*(n+1)/2/k-sum[j]);
			}
		}
		for (i=1;i<=k;i++)
		{
		    for (j=0;j<a[i].size()-1;j++)
		      printf("%d ",a[i][j]);
		    printf("%d\n",a[i][a[i].size()-1]);
		}
	}
	return 0;
}

1004 Enveloping Convex(待补)

1005 Good Numbers(待补)

1006 Horse(待补)

1007 Just an Old Puzzle(Solved By wtw/cys)

这一类问题似乎有一个判断是否能到最终状态的方法:根据逆序对个数和空位到最终位置的曼哈顿距离的和是否是偶数,若为偶数则有解;否则无解。

然后题解说120步一定能到终点。不是我写的,不太清楚。

1008 K-th Closest Distance(Solved By wtw/cys)

似乎是cys先对wtw说可以主席树,wtw:“你不要用这种垃圾算法来糊弄我。”(???

然后wtw写了二分+主席树,结果第一发WA,第二发T(此时比赛还剩一个半小时),后面又交了17发,基本都是T,还有几发WA。最后一小段时间他T到没办法了,准备改成离散化,没改完,到最后也没过。

赛后发现第二发那个T就能AC,后面很多发T也都是能AC的。。。(心疼,多自闭一个半小时。。。

具体解法等他写博客。

1009 Linear Functions(待补)

1010 Minimal Power of Prime(Solved By jlz)

考虑答案大于1的情况。

对于可表示为x^k的数,很显然我们可以很容易得到答案(比如枚举k,然后二分或者通过pow函数得到x)。

除了上述情况,要想答案为2,则至少含有两种素因子,且较小幂次为2。假设两个数分别为p,q,p^{2}*q^{3}\leq10^{18},若p\leq q,则显然有p\leq 10^{3.6}\approx 3981

因此,考虑先打出4000以内的素数表,然后枚举素数表分解n,得到分解部分p_{1}^{e_{1}}*p_{2}^{e_{2}}*...*p_{k}^{e_{k}}和未分解部分m,令ans0=min(e_{1},e_{2},...,e_{k}),ans1为m的答案,则最后答案为min(ans0,ans1)。

现在只需要考虑m。首先可以知道,m的最小素因子大于4000,则可知m不为1的情况可能为p^{2}*q^{2}p^{2}p^{3}p^{4}

先判m是否可表示为x^2

    如果可以,再看x是否可表示为y^2,若可以,则ans1=4;否则ans1=2。

    如果不可以,看x是否可表示为x^3,若可以,则ans1=3;否则ans1=1。

最后得到答案min(ans0,ans1)。

AC代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define db double
#define m_p make_pair
#define p_b push_back
#define For(i,a,b) for(int i=a;i<=b;i++)
#define ls (rt<<1)
#define rs ((rt<<1)|1)
#define mst(a,b) memset(a,b,sizeof(a))
const int maxn=4e3+5;
const db eps=1e-8;
const ll INF=1e18;
const int mod=1e9+7;
const int seed=131;
int t; 
ll x;
int prime[maxn],tot;
bool notprime[maxn];
void init(){
    notprime[1]=1;
    for(int i=2;i<maxn;i++){
        if(!notprime[i]) prime[tot++]=i;
        for(int j=0;j<tot&&prime[j]*i<maxn;j++){
            notprime[prime[j]*i]=1;
            if(i%prime[j]==0) break; 
        }
    }
}
int p[100],e[100],pcnt;
int main(){
//    freopen("in.txt","r",stdin);
    init();
    scanf("%d",&t);
    while(t--){
        scanf("%lld",&x);
        int ans=59,ans1=59;
        pcnt=0;
        for(int i=0;i<tot&&prime[i]<=x;i++){
            if(x%prime[i]==0){
                p[pcnt]=prime[i],e[pcnt]=0;
                while(x%prime[i]==0){
                    e[pcnt]++;
                    x/=prime[i];
                }
                ans=min(e[pcnt],ans);
                pcnt++;
            }
        }
        if(x==1||ans==1){
            cout<<ans<<"\n";
            continue;
        }
        int m=sqrt(x+0.5);
        if(m*1ll*m==x){
            int k=sqrt(m+0.5);
            if(k*k==m) ans1=4;
            else ans1=2;
        }
        else{
            m=pow(x,1.0/3);
            for(int i=m-1;i<=m+2;i++){
            	if(i*1ll*i*i==x){
            		ans1=3;break;
				}
			}
            if(ans1!=3) ans1=1;
        }
        ans=min(ans,ans1);
        cout<<ans<<"\n";
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值