20190731杭电多校第四场

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

贪心。

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

AC代码:

using namespace std;
#include
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

20190731杭电多校第四场_第1张图片

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

AC代码:

using namespace std;
#include
int t,x,i,j;
long long n,k; 
vector 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

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
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

 

你可能感兴趣的:(比赛合集)