2018CCPC网络赛部分题题解

通过这场比赛再次认识到自己的菜,被大佬们吊着锤。。。开场的一个小时节奏还算不错,先过了1004,1009也有思路。接着,服务器就炸了。。。交上去的一发也WA了,比赛中途居然在一直刷网页。。。还好1009把bug找出来A掉了。。。可是1003还是找不出规律啊,1010的dp还是不会优化啊,1001贪心也贪错了啊。。。

不说了,总结起来还是自己太弱了。。。(只能靠赛后补题来防止自己更菜了。。。)

-------------------------------------------------------------------------------------------------------------------------------------------------------

1004 -  Find Integer(hdu6441)

题意:找到一组b和c,使得a^n+b^n=c^n。没有输出-1,-1。

这题看一眼应该都想到费马大定理了。n>=3时是无解的。那么只看n=1和n=2即可,n=1是取b=1,c=a+1即可。关键在于n=2时,要想到勾股数的公式(1)当a为大于1的奇数2n+1时,b=2n^2+2n, c=2n^2 +2n+1(2)当a为大于4的偶数2n时,b=n^2-1, c=n^2+1

这个百度就可以了(逃)

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<cmath>
#include<cstdlib>
using namespace std; 
typedef long long ll;
int main()
{
    ll t,a,n;
    ll b,c;
    scanf("%lld",&t);
    while(t--)
    {
        scanf("%lld%lld",&n,&a);
        if(n>=3||n==0)
        printf("-1 -1\n");
        else
        {
            if(n==1)
            {
                printf("1 %lld\n",a+1);
            }
            else if(n==2)
            {
                 if(a%2==1)
                 {
                       n=a/2;
                       b=2*n*n+2*n;
                       c=b+1;
                  }
                  else
                  {
                        n=a/2;
                        b=n*n-1;
                        c=n*n+1;
                   }
                   printf("%lld %lld\n",b,c); 
            }
        } 
    }
    return 0;    
} 

1009  Tree and Permutation(hdu6446)

题意:从给出的序列的一个端点到另一个端点的费用即为s(i),求所有序列的全排列s(i)的和

 这题是队友想出来的,Orz果爷。。。

通过观察可以发现只要计算这个序列中任意两点距离的总和 乘上  2(n-1)f(n-2), 其中f(i)代表i的阶乘。

后面是怎么得到的呢?如(1 3)和(3 1)算了两次,所以乘2。后面的可以将此时选出来的两个数看成一个整体,一个组合数就搞定了(很像高中的排列组合题)。。。

那么任意两点间距离怎么算呢?其实对边统计就行了,对每条边而言,经过这条边的总次数就是这条边两边点数的乘积。所以这道题其实1遍dfs即可。。。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<cmath>
#include<cstdlib>
using namespace std;
#define ll long long
const ll mod = 1e9+7;
const int MAXN = 1e5+9;
int n;
ll ans, f[MAXN], cnt_son[MAXN];
struct node{
    int y;
    ll l;
};
vector<node>e[MAXN];
void dfs(int fa, int cur){
    cnt_son[cur]=1;
    ll l=0;
    for(int i=0; i<e[cur].size(); ++i){
        int son=e[cur][i].y;
        if(son==fa){
            l=e[cur][i].l;
            continue;
        }
        dfs(cur, son);
        cnt_son[cur]+=cnt_son[son];
        
    }
    ans=(ans+cnt_son[cur]*(n-cnt_son[cur])%mod*l%mod)%mod;
}
void solve(){
    int x, y;
    ll l;
    node t;
    for(int i=1; i<=n; ++i){
        e[i].clear();
    }
    if(1==n){
        puts("0");
        return;
    }
    for(int i=1; i<n; ++i){
        scanf("%d%d%lld", &x, &y, &l);
        t.y=y, t.l=l;
        e[x].push_back(t);
        t.y=x, t.l=l;
        e[y].push_back(t);
    }
    ans=0;
    dfs(-1, 1);
    ans=ans*(n-1)%mod*2%mod*f[n-2]%mod;
    printf("%lld\n", ans);
}
void init(){
    f[0]=1;
    for(int i=1; i<MAXN; ++i){
        f[i]=f[i-1]*(ll)i%mod;
    }
}
int main(){
    init();
    while(scanf("%d", &n)!=EOF){
        solve();
    }
    return 0;
}

1003   Dream (hdu6440)

题意:不说了(哭),场上读了一小时也不懂,英语弱菜。。。

这题结论好简单啊,就是在加法和乘法基础上取个模就好了。。。

不过你能想到?(大佬请无视)

弱弱的我还是不会证。。。

代码: 

#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
int main()
{
	int t,p;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&p);
		for(int i=0;i<p;i++)
		{
			printf("%d",(i+0)%p);
			for(int j=1;j<p;j++)
			{
				 printf(" %d",(i+j)%p);
			}
			printf("\n");
		}
		for(int i=0;i<p;i++)
		{
			printf("%d",(i*0)%p);
			for(int j=1;j<p;j++)
			{
				 printf(" %d",(i*j)%p);
			}
			printf("\n");
		}
	}
	return 0;
} 

1010   YJJ's Salesman (hdu6447)

题意:从(0,0)出发到(1e9,1e9),途中不走回头路且只能向下,右,右下走,且只有想右下走时能拿钱,求最多拿多少钱

dp转移很好像,很明显TLE+MLE。首先必然离散化,由于我太弱了,二维的离散化之前没怎么写过,比赛时很生疏。。。

离散完后思路还是明显的,j表示当前所在列(这里需要从右往左,从上往下扫,和01背包的优化相似)f[j]代表当前列最大值,即f[j]=max(f[1]~f[i]+v[num],f[j])(1=<i<j)

看到了维护区间最大值,线段树或BIT搞一下就可以了

代码:

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
using namespace std;
typedef long long ll;
const int MAXN=1e5+10;
typedef struct
{
	ll x;
	ll y;
	ll v;
}  Node;
Node node[MAXN];
ll nx[MAXN];
ll ny[MAXN];
ll MAX[MAXN<<2];
ll Max;
int tx,ty;
int t,n;
bool cmp(Node a,Node b)
{
	if(a.x==b.x)
	return a.y>b.y;
	else
	return a.x<b.x;
}
void PushUP(int rt) {
       MAX[rt] = max(MAX[rt<<1] , MAX[rt<<1|1]);
}
void update(int p,ll sc,int l,int r,int rt) {
       if (l == r) {
              MAX[rt] = sc;
              return ;
       }
       int m = (l + r) >> 1;
       if (p <= m) update(p , sc , lson);
       else update(p , sc , rson);
       PushUP(rt);
}
ll query(int L,int R,int l,int r,int rt) {
       if (L <= l && r <= R) {
              return MAX[rt];
       }
       int m = (l + r) >> 1;
       ll ret = 0;
       if (L <= m) ret = max(ret , query(L , R , lson));
       if (R > m) ret = max(ret , query(L , R , rson));
       return ret;
}
int main()
{
	int cntx,cnty;
	ll  tem,ans;
	scanf("%d",&t);
	while(t--)
	{
		 cntx=cnty=0;
		 memset(MAX,0,sizeof(MAX));
		 scanf("%d",&n);
		 for(int i=1;i<=n;i++)
		 {
		 	 scanf("%lld%lld%lld",&node[i].x,&node[i].y,&node[i].v);
		 	 nx[++cntx]=node[i].x;
		 	 ny[++cnty]=node[i].y;
		 }
		 sort(nx+1,nx+1+cntx);
		 sort(ny+1,ny+1+cnty);
		 tx=unique(nx+1,nx+cntx+1)-(nx+1);
		 ty=unique(ny+1,ny+cnty+1)-(ny+1);
		 for(int i=1;i<=n;i++)
		 {
		 	 node[i].x=lower_bound(nx+1,nx+cntx+1,node[i].x)-nx;
		 	 node[i].y=lower_bound(ny+1,ny+cnty+1,node[i].y)-ny;
		 }
        sort(node+1,node+1+n,cmp);
        printf("%d %d\n",tx,ty);
        int y;
        ans=0;
        for(int i=1;i<=n;i++)
        {
        	 y=node[i].y;
        	 if(y!=1)
         	{
				Max=query(y,y,1,n,1);
				tem=max(Max,query(1,y-1,1,n,1)+node[i].v);
				update(y,tem,1,n,1);
				ans=max(ans,tem);
			}
			 else
			 {
			 	  Max=query(y,y,1,n,1);
				  tem=node[i].v;
				  update(y,tem,1,n,1);
				  ans=max(ans,tem);
			 }
		 }
         printf("%lld\n",ans);
	}
	return 0;
}

1001  Buy and Resell  (hdu6438)

思路:每个地方有一个价格,可以在每个地方选择买,卖,或不买不卖。同时可携带多个商品,初始钱无限,问最多赚多少钱。

和   http://codeforces.com/problemset/problem/867/E差不多,

可以看看这篇题解

https://blog.csdn.net/qq_28954601/article/details/78146932

唯一不同的是这题要求交换次数最小。其实也好像,比如1 -> 2 ->5 -> 10,中间多算了2和5,那么把他们减掉就可以了。也就是对于既卖又买的点减掉即可。。。

代码:

#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
const int MAXN=1e5+10;
priority_queue<ll, vector<ll>, greater<ll> > q; 
map<ll,int> mp;
int main()
{
	int t,n;
	ll tem,ans,tt;
	int cnt;
	scanf("%d",&t);
	while(t--)
	{
	     scanf("%d",&n);
	     cnt=0;
	     ans=0;
	     mp.clear();
	     while(!q.empty())
	     q.pop();
		 for(int i=1;i<=n;i++)
	   {
		    scanf("%lld",&tem);
		    if(q.empty())
		    {
		    	q.push(tem);
			}
			else
			{
				   if(q.top()>=tem)
			    {
				     q.push(tem);
			    }
			       else
			    {
				     tt=q.top();
				     cnt+=2;
				     q.pop();
				     q.push(tem);
				     q.push(tem);
				     ans+=(tem-tt);
				     if(mp[tt]>0)
				     {
				     	 mp[tt]--;
						 cnt-=2;
					 }
					 mp[tem]++;
			    }
			}
	   }
	   printf("%lld %d\n",ans,cnt);
    }
	return 0;
}

其实还想补个1007,但由于我太弱了,等过两天再补,待更。。。 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值