Asia - Changchun 5:00:00

本文记录了一次组队赛的经历,虽然只解决了两道题目,但详细解析了其中的2-SAT问题、蘑菇采摘问题及征服新区问题等算法挑战。通过实战分享,加深了对算法的理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这是我们分组后Dots_lzl小组第一次参加组队赛,也是很开心的一次,虽然只A了2道题目(本来应该是三道的,已经AC了,但是却说时间到了,居然说是因为比赛提前开始了几分钟,我们就是在最后几分钟A的呀,别的组WA20多次,我们5次过的题目,他居然封榜了),以下仅有C,E,K是我们组做的

B -Bit Magic


本题很简单,明显的2-SAT的模版题。
这题是2-SAT。只不过模板写错了一点,多加了个分号,导致样例一直出不来。幸好调试之后发现,
修改一下,交上去1A,爽~~~~此题是做得最顺利的了。

现场赛的时候内存真的是无穷大啊,直接做31*500*2=31000个点的2-SAT就AC了。但是比赛结束后在ZOJ上就会MLE了~~~~~
要分开做,做31次的2-SAT就可以了~~~~~~






#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<string.h>
using namespace std;

const int MAXN=1100;//

bool visit[MAXN];
queue<int>q1,q2;
//vector建图方法很妙
vector<vector<int> >adj; //原图    //中间一定要加空格把两个'>'隔开
vector<vector<int> >radj;//逆图
vector<vector<int> >dag;//缩点后的逆向DAG图
int n,m,cnt;

int id[MAXN],order[MAXN],ind[MAXN];//强连通分量,访问顺序,入度

void dfs(int u)
{
    visit[u]=true;
    int i,len=adj[u].size();
    for(i=0;i<len;i++)
      if(!visit[adj[u][i]])
        dfs(adj[u][i]);
    order[cnt++]=u;
}
void rdfs(int u)
{
    visit[u]=true;
    id[u]=cnt;
    int i,len=radj[u].size();
    for(i=0;i<len;i++)
      if(!visit[radj[u][i]])
        rdfs(radj[u][i]);
}
void korasaju()
{
    int i;
    memset(visit,false,sizeof(visit));
    for(cnt=0,i=0;i<2*n;i++)
      if(!visit[i])
        dfs(i);
    memset(id,0,sizeof(id));
    memset(visit,false,sizeof(visit));
    for(cnt=0,i=2*n-1;i>=0;i--)
      if(!visit[order[i]])
      {
          cnt++;//这个一定要放前面来
          rdfs(order[i]);
      }
}
bool solvable()
{
    for(int i=0;i<n;i++)
      if(id[2*i]==id[2*i+1])
        return false;
   return true;
}

void add(int x,int y)
{
    adj[x].push_back(y);
    radj[y].push_back(x);
}

int b[600][600];
int bit[33];
int main()
{
    int N;
    bit[0]=1;
    for(int i=1;i<31;i++)bit[i]=2*bit[i-1];
    while(scanf("%d",&N)!=EOF)
    {
        n=N;
        bool flag=true;
        for(int i=0;i<N;i++)
          for(int j=0;j<N;j++)
          {
                scanf("%d",&b[i][j]);
                if(i==j&&b[i][j]!=0)flag=false;
            }
        if(!flag)
        {
            printf("NO\n");
            continue;
        }
        for(int i=0;i<N;i++)
        {
            if(!flag)break;
            for(int j=i+1;j<N;j++)
              if(b[i][j]!=b[j][i])
              {
                    flag=false;
                    break;
                }
        }
        if(!flag)
        {
            printf("NO\n");
            continue;
        }
        for(int k=0;k<31;k++)
        {
            adj.assign(2*n,vector<int>());
            radj.assign(2*n,vector<int>());
            for(int i=0;i<N;i++)
                for(int j=i+1;j<N;j++)
                {
                    if(i%2==1&&j%2==1)
                    {
                        int t1=i;
                        int t2=j;
                        if(b[i][j]&bit[k])
                        {
                            add(2*t1,2*t2+1);
                            add(2*t2,2*t1+1);
                        }
                        else
                        {
                            add(2*t1+1,2*t1);
                            add(2*t2+1,2*t2);
                        }
                    }
                    else if(i%2==0&&j%2==0)
                    {
                        int t1=i;
                        int t2=j;
                        if(b[i][j]&bit[k])
                        {
                            add(2*t1,2*t1+1);
                            add(2*t2,2*t2+1);
                        }
                        else
                        {
                            add(2*t1+1,2*t2);
                            add(2*t2+1,2*t1);
                        }
                    }
                    else
                    {
                        int t1=i;
                        int t2=j;
                        if(b[i][j]&bit[k])
                        {
                            add(2*t1,2*t2+1);
                            add(2*t1+1,2*t2);
                            add(2*t2,2*t1+1);
                            add(2*t2+1,2*t1);
                        }
                        else
                        {
                            add(2*t1,2*t2);
                            add(2*t1+1,2*t2+1);
                            add(2*t2,2*t1);
                            add(2*t2+1,2*t1+1);
                        }

                    }
                }
            korasaju();
            if(!solvable())
            {
                flag=false;
                break;
            }
        }
        if(flag)printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}









C -The Little Girl who Picks Mushrooms

#include<stdio.h>
#include<string.h>
#define max(a , b) (a)>(b)?(a):(b)

int main()
{
   	int a[5] , d[10][5]={0,1,2,3,4,0,1,3,2,4,0,1,4,2,3,0,2,3,1,4,0,2,4,1,3,0,3,4,1,2,1,2,3,0,4,1,2,4,0,3,1,3,4,0,2,2,3,4,0,1};
    int n , M , i , j , temp ,flag;
    while(scanf("%d",&n)!=EOF)
    {
		M=0;
        memset(a , -1 , sizeof(a));
        for(i=0 ; i<n ; i++)
          scanf("%d",&a[i]);
        for(i=0;i<10;i++)
        {
			temp=flag=0;
            for(j=0 ; j<3 ; j++)
            if(a[d[i][j]]==-1)
            {
				flag=1;
                break;
            }
            else
            	temp += a[d[i][j]];          
            j=3;
            if(flag)
            {
				temp=0;
               	for(j ; j<5 ; j++)
                if(a[d[i][j]]==-1)
                {
                     M=1024;
                     break;
                }
                else
                {
                	temp += a[d[i][j]];
                }
               	if(M==1024)
					break;
               	while(temp>1024) 
			   		temp -= 1024;
			    M=max(M,temp);
            }
            else
            {
                if(temp%1024==0)
                {
                   temp=0;
                   for(j ; j<5 ; j++)
                   if(a[d[i][j]]==-1)
                   {
 
                       M=1024;
                       break;
                   }
                   	else
                        temp += a[d[i][j]];
	                if(M==1024)
						break;
                   	while(temp>1024) 
				   		temp -= 1024;
                    M=max(M , temp);
 
                }
            }
 
          }
       printf("%d\n" , M);
    }
    return 0;
}








#include<stdio.h>//这个是转的
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
int a[6];
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        int sum=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            sum+=a[i];
        }
        if(n>=0&&n<=3)
        {
            printf("1024\n");
            continue;
        }
        int ans=0;
        if(n==5)
        {
            for(int i=0;i<5;i++)
              for(int j=i+1;j<5;j++)
                for(int k=j+1;k<5;k++)
                if((a[i]+a[j]+a[k])%1024==0)
                 {
                     int temp=sum-a[i]-a[j]-a[k];
                     while(temp>1024)temp-=1024;
                     if(temp>ans)ans=temp;
                 }
            printf("%d\n",ans);
            continue;
        }

        if(n==4)
        {
            ans=0;
            for(int i=0;i<4;i++)
              for(int j=i+1;j<4;j++)
                for(int k=j+1;k<4;k++)
                  if((a[i]+a[j]+a[k])%1024==0)
                  {
                      ans=1024;
                  }
            if(ans>0)
            {
                printf("1024\n");
                continue;
            }
            for(int i=0;i<4;i++)
              for(int j=i+1;j<4;j++)
              {
                  int temp=a[i]+a[j];
                  while(temp>1024)temp-=1024;
                  if(temp>ans)ans=temp;
              }
            printf("%d\n",ans);
            continue;
        }
    }
    return 0;
}



E -Conquer a New Region

  # include<cstdio>
  # include<cstring>
  # include<algorithm>
  const int maxn=200001;
  using namespace std;
  struct Edge
  {
      int u,v,w;
  }edge[maxn];
 int f[maxn],num[maxn];
 long long cost[maxn];
 int find(int x)
 {
     /*if(f[u]==u) return u;
     return f[u] = find(f[u]);*/
     return x==f[x]?x:find(f[x]);
 }
 bool cmp(struct Edge a,struct Edge b)
 {
     return a.w > b.w;
 }
 int main()
 {
     int n,i;
     while(scanf("%d",&n)!=EOF)
     {
         for(i=1;i<n;i++)
         scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
         sort(edge+1,edge+n,cmp);
         for(i=1;i<=n;i++)
         	f[i] = i, num[i]=1, cost[i]=0;
         for(i=1;i<n;i++)
         {
             int x1=find(edge[i].u);
             int x2=find(edge[i].v);
             if(x1!=x2)
             {
                 cost[x2] = max((long long)num[x1]*edge[i].w+cost[x2],(long long)num[x2]*edge[i].w+cost[x1]);
                 num[x2]+=num[x1];
                 f[x1]=x2;
             }
         }
         printf("%lld\n",cost[find(1)]);
     }
     return 0;
 }
 












H -Math Magic

很水的DP,长春赛的时候竟然没有做出来。。。。。方向是写对了的,只是最后半个小时写的,很紧张。最后超时了。

需要注意些细节,一些初始化才不会超时。

预处理出LCM[1000][1000]来。

dp[now][i][j]表示当前状态下,和为i,LCM为j的解的个数。递推K次就出答案了

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<iostream>
using namespace std;
const int MOD=1000000007;
int dp[2][1010][1010];

int num[1000];

int gcd(int a,int b)
{
    if(b==0)return a;
    return gcd(b,a%b);
}
int lcm(int a,int b)
{
    return a/gcd(a,b)*b;
}
int LCM[1010][1010];
int main()
{
    int n,m,k;
    for(int i=1;i<=1000;i++)
      for(int j=1;j<=1000;j++)
        LCM[i][j]=lcm(i,j);


    while(scanf("%d%d%d",&n,&m,&k)!=EOF)
    {
        int cnt=0;
        for(int i=1;i<=m;i++)
        {
            if(m%i==0)
               num[cnt++]=i;
        }
        int now=0;
        //memset(dp[now],0,sizeof(dp[now]));
        for(int i=0;i<=n;i++)
          for(int j=0;j<cnt;j++)
            dp[now][i][num[j]]=0;
        dp[now][0][1]=1;

        for(int t=1;t<=k;t++)
        {
            now^=1;
           // memset(dp[now],0,sizeof(dp[now]));
          for(int i=0;i<=n;i++)
            for(int j=0;j<cnt;j++)
              dp[now][i][num[j]]=0;
            for(int i=t-1;i<=n;i++)
              for(int j=0;j<cnt;j++)
              {
                  if(dp[now^1][i][num[j]]==0)continue;
                  for(int p=0;p<cnt;p++)
                  {
                      int x=i+num[p];
                      //int y=lcm(num[j],num[p]);
                      int y=LCM[num[j]][num[p]];
                      if(x>n||m%y!=0)continue;
                      dp[now][x][y]+=dp[now^1][i][num[j]];
                      dp[now][x][y]%=MOD;
                  }
              }
        }
        printf("%d\n",dp[now][n][m]);
    }
    return 0;
}












J -Split the Rectangle

其实这题是不难的,注意是看懂题目意思。

只要按照加入的边建立树。

然后每次的查询就是求出这个点所在的叶子结点编号。然后求出这两个叶子结点的LCA,暴力求LCA即可。

然后答案就是 n+1-(LCA所在结点下面的叶子结点个数)+1

 

很好的一道题。

注意给的点是没有顺序的。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<math.h>
using namespace std;
const int MAXN=2020;

struct Node
{
    int lson,rson,father;
    int dep;//深度
    int xl,yl,xr,yr;
    void init(int de,int f)
    {
        lson=rson=0;
        father=f;
        dep=de;
    }
    void update(int a,int b,int c,int d)
    {
        xl=a;yl=b;xr=c;yr=d;
    }
}node[MAXN];//结点
int tol;
int num[MAXN];//每个结点下的叶子结点个数

int root;//根结点

int find(int root,int x,int y)
{
    int tmp=root,tt;
    while(1)
    {
        if(node[tmp].lson==0)return tmp;
        tt=node[tmp].lson;
        if(x<=node[tt].xr&&x>=node[tt].xl&&y>=node[tt].yl&&y<=node[tt].yr)tmp=tt;
        else tmp=node[tmp].rson;
    }
}

int get_num(int now)
{
    num[now]=0;
    if(node[now].lson==0)
    {
        return num[now]=1;
    }
    else
    {
        num[now]+=get_num(node[now].lson);
        num[now]+=get_num(node[now].rson);
    }
    return num[now];
}

int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int xl,yl,xr,yr;
    int n,q;

    while(scanf("%d%d%d%d",&xl,&yl,&xr,&yr)!=EOF)
    {
        root=0;
        node[root].init(0,-1);
        node[root].update(xl,yl,xr,yr);
        tol=1;
        scanf("%d%d",&n,&q);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d%d",&xl,&yl,&xr,&yr);
            if(xl>xr)swap(xl,xr);
            if(yl>yr)swap(yl,yr);
            int pos=find(root,(xl+xr)/2,(yl+yr)/2);
            int dep=node[pos].dep;

            node[pos].lson=tol;
            node[tol].init(dep+1,pos);
            node[tol].update(node[pos].xl,node[pos].yl,xr,yr);
            tol++;

            node[pos].rson=tol;
            node[tol].init(dep+1,pos);
            node[tol].update(xl,yl,node[pos].xr,node[pos].yr);
            tol++;
        }
        get_num(root);
        while(q--)
        {
            scanf("%d%d%d%d",&xl,&yl,&xr,&yr);
            int tmp1=find(root,xl,yl);
            int tmp2=find(root,xr,yr);

            while(tmp1!=tmp2)
            {
                if(node[tmp1].dep<node[tmp2].dep)tmp2=node[tmp2].father;
                else if(node[tmp1].dep>node[tmp2].dep)tmp1=node[tmp1].father;
                else
                {
                    tmp1=node[tmp1].father;
                    tmp2=node[tmp2].father;
                }
            }
            printf("%d\n",n+1-num[tmp1]+1);
        }
    }
    return 0;
}














K -Yukari's Birthday

// File Name: eee.cpp
// Author: rudolf
// Created Time: 2013年04月17日 星期三 19时16分37秒

#include<math.h>
#include<stdio.h>
#define LL long long

LL Pow(int x ,int  y)
{   
	int i;
	LL sum=1;
     for(i=0;i<y;i++ ) 
        sum *= x ;
   return sum ;
}

int main()
   {
	    
		LL n,le,ri,k,mid,ans;
        LL i , j,r;
        while(scanf("%lld",&n)!= EOF)
		{    
              r=1;
			  k=n-1;
			  for(i=2;i<=46;i++)
		    {
                  
				  le = 2 ;
				  ri = pow(n,1.0/i);
                  
                  while(le<=ri)
                 {
                          mid=(LL)(le+ri)/2;    
					     ans = (mid-Pow(mid,i+1))/(1-mid);
                     if(ans==n|| ans==(n - 1))
                      {
						  if(r*k>i*mid)
                          {
							  r=i;
							  k=mid;
						  }
							  break;
					  }
					 else if(ans > n)
						     ri = mid - 1;
					     else 
							le = mid + 1;
				 }

		  }        
			printf("%lld %lld\n",r,k);

	   }
return 0;
}




                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值