BITACM2018第一轮积分赛(三)题解

A. 很会dp

出题人: zhber
AC/TOT: 1/50

题解: 因为 V V V 实在太大了,所以做背包 d p dp dp 肯定不行,这一点在题目中已经很明显的提示了。那么另一种做法只能是暴力枚举每一个物品取还是不取。每件物品可以选取或不取,这样方案数会有 2 n 2^n 2n,是不能接受的。注意到如果 n n n 变成 n 2 \frac{n}{2} 2n,暴力枚举似乎就可以接受了。再考虑到如果 n n n 件物品分成两部分,分别以 2 n 2 2^\frac{n}{2} 22n 枚举这两部分的所有可能的体积之和,合并的时候不需要在两区间枚举各取什么再加起来,因为这样还是 2 n 2^n 2n,而对于一个区间枚举取的是什么体积(假如取了体积是 s u m sum sum ),另一个区间排序之后直接二分小等于 V − s u m V-sum Vsum 的最大值即可。显然只有这个值对于 s u m sum sum 才是有用的,其他值要么加起来超过 V V V,要么加起来不如它优。因此对 n n n 个物品折半之后分别暴力处理所有可能体积,然后枚举前半部分,在后半部分二分即可。这个算法有个专门的名字,叫meet-in-middle有兴趣的同学可以去学习一下“折半搜索”!

参考代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,len;
ll a[40],V,ans;
ll s[200010];
inline ll bsearch(int l,int r,ll x)
{
    ll t=0;
    while (l<=r)
    {
        int mid=(l+r)>>1;
        if (s[mid]<=x)t=s[mid],l=mid+1;
        else r=mid-1;
    }
    return t;
}
int main()
{
    scanf("%d%lld",&n,&V);
    for (int i=1;i<=n;i++)scanf("%lld",a+i);
    for (int i=0;i<(1<<(n/2));i++)
    {
        ll sum=0;
        for (int j=1;j<=n/2;j++)
            if (i & (1<<(j-1)) )sum+=a[j];
        if(sum<=V)s[++len]=sum;
    }
    s[++len]=0;
    sort(s+1,s+len+1);
    ans=s[len];
    for (int i=0;i<(1<<(n-n/2));i++)
    {
        ll sum=0;
        for (int j=n/2+1;j<=n;j++)
            if (i & (1<<(j-n/2-1)) )sum+=a[j];
        if(sum<=V)ans=max(ans,sum+bsearch(1,len,V-sum));
    }
    printf("%lld\n",ans);
}
B. 秀外慧中

出题人: zhber
AC/TOT: 0/0

题解: 注意到只要各位有一个零,那么乘积就是零了。因此 t t t是零与非零的情况分类讨论。

  • 对于乘积为零的情况,考虑到用总方案数减去不合法方案数,即得到合法的方案数。总方案数是 1 0 k 10^k 10k,不合法方案就是 k k k 位都不是零,共 9 k 9^k 9k 个。所以答案就是 1 0 k − 9 k 10^k-9^k 10k9k。注意答案取模必须是非负的。
  • 对于乘积不为零的情况,注意到填的数字只能是 1...9 1...9 1...9,那么 t t t分解质因数其实只能有 2 、 3 、 5 、 7 2、3、5、7 2357 四个质因数,否则一定无解。如果 t = 2 a 3 b 5 c 7 d t=2^a3^b5^c7^d t=2a3b5c7d,只要取 k k k 个数,乘起来得到 a a a 2 2 2 b b b 3 3 3 c c c 5 5 5 d d d 7 7 7 即可。

考虑动态规划: f [ i ] [ j ] [ k ] [ l ] [ m ] f[i][j][k][l][m] f[i][j][k][l][m]表示前 i i i个位置、已经有 j j j 2 2 2 k k k 3 3 3 l l l 5 5 5 m m m 7 7 7 的方案数,考虑取 1...9 1...9 1...9 每个数能贡献几个什么数字即可,比如 6 6 6 贡献了 1 1 1 2 2 2 1 1 1 3 3 3,因此 f [ i ] [ j ] [ k ] [ l ] [ m ] + = f [ i − 1 ] [ j − 1 ] [ k − 1 ] [ l ] [ m ] f[i][j][k][l][m]+=f[i-1][j-1][k-1][l][m] f[i][j][k][l][m]+=f[i1][j1][k1][l][m],其他 8 8 8 个式子同理。最后答案即为 f [ k ] [ a ] [ b ] [ c ] [ d ] f[k][a][b][c][d] f[k][a][b][c][d]。而 2 27 ≈ 3 17 ≈ 5 12 ≈ 7 10 ≈ 1 0 8 2^{27}\approx3^{17}\approx5^{12}\approx7^{10}\approx10^8 227317512710108,所以 a 、 b 、 c 、 d a、b、c、d abcd不会很大。

参考代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=1e9+7;
int n,t;
int p[20],q[20],len;
ll f[50][30][20][15][15];
int main()
{
    scanf("%d%d",&n,&t);
    if (t==0)
    {
        int s1=1,s2=1;
        for (int i=1;i<=n;i++)s1=(s1*10)%mod,s2=(s2*9)%mod;
        printf("%d\n",(s1-s2+mod)%mod);
        return 0;
    }
    for (int i=2;i*i<=t;i++)
    if (t%i==0)
    {
        p[++len]=i;q[len]=1;t/=i;
        while (t%i==0)t/=i,q[len]++;
    }
    if (len==0||t!=1)
    {
        p[++len]=t;
        q[len]=1;
    }
    for (int i=1;i<=len;i++)if (p[i]!=1&&p[i]!=2&&p[i]!=3&&p[i]!=5&&p[i]!=7){puts("0");return 0;}
    int a=0,b=0,c=0,d=0;
    for(int i=1;i<=len;i++)
    {
        if (p[i]==2)a=q[i];
        if (p[i]==3)b=q[i];
        if (p[i]==5)c=q[i];
        if (p[i]==7)d=q[i];
    }
    f[0][0][0][0][0]=1;
    for (int i=1;i<=n;i++)
        for (int j=0;j<=a;j++)
            for (int k=0;k<=b;k++)
                for(int l=0;l<=c;l++)
                    for (int m=0;m<=d;m++)
                    {
                        f[i][j][k][l][m]+=f[i-1][j][k][l][m];//1
                        if (j>=1)f[i][j][k][l][m]+=f[i-1][j-1][k][l][m];//2
                        if (k>=1)f[i][j][k][l][m]+=f[i-1][j][k-1][l][m];//3
                        if (j>=2)f[i][j][k][l][m]+=f[i-1][j-2][k][l][m];//4
                        if (l>=1)f[i][j][k][l][m]+=f[i-1][j][k][l-1][m];//5
                        if (j>=1&&k>=1)f[i][j][k][l][m]+=f[i-1][j-1][k-1][l][m];//6
                        if (m>=1)f[i][j][k][l][m]+=f[i-1][j][k][l][m-1];//7
                        if (j>=3)f[i][j][k][l][m]+=f[i-1][j-3][k][l][m];//8
                        if (k>=2)f[i][j][k][l][m]+=f[i-1][j][k-2][l][m];//9
                        f[i][j][k][l][m]%=mod;
                    }
    printf("%lld\n",f[n][a][b][c][d]);
}
C. 背着大家偷偷交题

出题人: zhber
AC/TOT: 0/0

题解: 把所有熟人的位置扔进队列,然后做 b f s bfs bfs 往外扩展,即可知道每个点到它最近熟人的距离 d i s t [ i ] [ j ] dist[i][j] dist[i][j]。显然如果存在一条最小距离是 k k k 的路径,也肯定存在一条最小距离是 k − 1 k-1 k1 的路径,因此最大的最小距离会在 [ k , + ∞ ) [k,+\infty) [k,+)。而如果不存在最小距离是 k k k 的路径,那也一定不存在最小距离是 k + 1 k+1 k+1 的路径,因此最大的最小距离会在 [ 0 , k ) [0,k) [0,k)。因此可以二分最小距离,不管我们判断某个答案可不可行,一定可以将范围至少缩小一半。考虑判定最小距离 m i d mid mid 可不可行,此时只能走满足 d i s t [ x ] [ y ] ≥ m i d dist[x][y]\ge mid dist[x][y]mid 的点 ( x , y ) (x,y) (x,y),相当于在原有条件下多了一个合法性的判定。在此条件下, b f s bfs bfs S S S T T T 的最短距离即可。

参考代码:

#include<bits/stdc++.h>
#define pa pair<int,int>
#define mkp make_pair
using namespace std;
char mp[1010][1010];
int dist[1010][1010];
int dis2[1010][1010];
int n,m;
int sx,sy,ex,ey;
int mx[4]={1,0,-1,0},my[4]={0,1,0,-1};
inline void bfs1()
{
    memset(dist,-1,sizeof dist);
    queue<pa>q;while (!q.empty())q.pop();
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            if (mp[i][j]=='#')q.push(mkp(i,j)),dist[i][j]=0;
    while (!q.empty())
    {
        int nx=q.front().first,ny=q.front().second;q.pop();
        for (int k=0;k<4;k++)
        {
            int wx=nx+mx[k];
            int wy=ny+my[k];
            if (wx<1||wx>n||wy<1||wy>m||dist[wx][wy]!=-1)continue;
            dist[wx][wy]=dist[nx][ny]+1;
            q.push(mkp(wx,wy));
        }
    }
}
inline int bfs2(int x)
{
    memset(dis2,-1,sizeof dis2);
    queue<pa>q;while (!q.empty())q.pop();
    q.push(mkp(sx,sy));dis2[sx][sy]=0;
    while (!q.empty())
    {
        int nx=q.front().first,ny=q.front().second;q.pop();
        for (int k=0;k<4;k++)
        {
            int wx=nx+mx[k];
            int wy=ny+my[k];
            if (wx<1||wx>n||wy<1||wy>m||dis2[wx][wy]!=-1||dist[wx][wy]<x)continue;
            dis2[wx][wy]=dis2[nx][ny]+1;
            q.push(mkp(wx,wy));
        }
    }
    return dis2[ex][ey];
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)scanf("%s",mp[i]+1);
    for (int i=1;i<=n;i++)
    {
        for (int j=1;j<=m;j++)
            if (mp[i][j]=='S')sx=i,sy=j;
            else if (mp[i][j]=='T')ex=i,ey=j;
    }
    bfs1();
    int l=0,r=2*n-1,ans=0,ans2=0;
    while (l<=r)
    {
        int mid=(l+r)>>1,cal=bfs2(mid);
        if (cal!=-1)ans=mid,ans2=cal,l=mid+1;
        else r=mid-1;
    }
    printf("%d %d\n",ans,ans2);
}
D. I Love Diamond Forever.jpg

出题人: konnyaku
AC/TOT: 8/52

题解:

diamond裸 dp,不会就把讲 dp 的学长拖出去枪毙五分钟 。 ——天爸爸

卖完萌还是讲一下吧,分析一下问题,钻石血量多少不会影响它受多少伤害,反而一旦月狗质量确定,则钻石受的伤害是确定的,明白了这一点,这符合动态规划的子问题性质,考虑 f ( i ) f(i) f(i) 表示一只血量为 i i i 的月狗能对钻石造成的最小伤害,它下一轮只会转移到 f ( i ) → f ( i − k ) + f ( k ) ,   0 &lt; k &lt; i f(i)\to f(i-k)+f(k),\ 0&lt; k&lt; i f(i)f(ik)+f(k), 0<k<i 枚举 k k k 就好了,而且因为有对称性, k k k 只需要枚举到 [ i 2 ] [\frac{i}{2}] [2i] 就好了,由于 N N N M M M 都很大我们可以考虑记忆化搜索。

参考代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e3 + 5;
int a[maxn];
ll f[maxn];
ll DP(int i) {
    if (f[i] != -1) return f[i];
    if (i == 1) return 0;
    ll ans = 1e18;
    for (int k = 1; k <= i / 2; k++) ans = min(ans, DP(k) + DP(i - k) + a[k] + a[i - k]);
    return f[i] = ans;
}
int main() {
    int m, n;
    cin >> m >> n;
    a[1] = 0;
    for (int i = 2; i <= m; i++) cin >> a[i];
    memset(f, -1, sizeof f);
    ll res = DP(m);
    if (res >= n) {
        puts("NO");
        cout << res - n + 1 << endl;
    } else {
        puts("YES");
        cout << n - res << endl;
    }
    return 0;
}
E. 线段数不清了QAQ

出题人: cwhbbt
AC/TOT: 29/64

题解:

  • 先考虑 0 0 0 为左端点, n n n 为右端点这片区域的所有小线段:它们两两匹配,所构成的 X X X 线总数为 n n n
  • 再考虑以 1 1 1 为左端点, n − 1 n-1 n1 为右端点这片区域的所有小线段:它们两两匹配,所构成的 X X X 线总数为 n − 2 n-2 n2
  • 以此类推…累加即可

观察以后不难推出答案为 n + 1 2 ⋅ [ n − ( n − 1 ) 2 ] \frac{n+1}{2}·[n-\frac{(n-1)}{2}] 2n+1[n2(n1)]

参考代码:

#include<bits/stdc++.h>
using namespace std;

int main() {
  int n;
  while(cin>>n) cout<<(n+1)/2*(n-(n-1)/2)<<endl;
  return 0;
}
F. 龙神和平行四边形

出题人: sadyi98
AC/TOT: 1/23

题解:

  • 我们先不考虑要拆线段的情况,由于平行四边形对边相等,所以该题就是要我们找有多少对线段长度是相等的,再将数量除二下取整就可以了。
  • 再考虑要拆线段的情况,简单分析一下就可以知道,如果我们拆的是某一对边中的一条,根本没有什么**用,那我们就只需要考虑剩下的所有单个的边的情况:
    • 当我们有两条以上的孤立边的时候,显然我们至少可以将较大的线段截成较小的线段组成一对。
    • 然后我们考虑更多的情况,如果我们能在孤立边中找到某一条线段是其他两条线段之和,那我们可以多凑出两对相等的线段。
    • 当我们只有一条孤立边的时候,如果该孤立边是偶数长度,则其也可拆成一对相等的线段。
  • 再回到之前的数量除二下取整就可以得出答案。

参考代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<vector>
#include<set>

#define mem(a,b) memset((a),(b),sizeof(a))

using namespace std;

const double pi=acos(-1.0);
int l[2005];
map<int,int> m;
vector<int> v1;
vector<int> v2;
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		scanf("%d",&l[i]);
	}
	sort(l,l+n);
	l[n]=-1;
	int temp=0;
	for(int i=0;i<n;i++)
	{
		if(l[i+1]==l[i])
		{
			i++;
			v2.push_back(l[i]);
			temp++;
			continue;
		}
		else
		{
			m[l[i]]=1;
			v1.push_back(l[i]);
		}
	}
	int flag=0;
	for(int i=0;i<v1.size()&&flag==0;i++)
	{
		for(int j=i;j<v1.size()&&flag==0;j++)
		{
			if(m.count(v1[i]+v1[j]))
			{
				flag=2;
			}
		}
	}
	if(flag==0&&v1.size())
	{
		if(v1.size()>1||(v1[0]&1)==0)flag=1;
	}
	printf("%d\n",(temp+flag)/2);
}
G. 丑闻传播计划

出题人: sairyo
AC/TOT: 1/25

题解: 考虑两遍 b f s bfs bfs 处理这个关系图——

  • 第一遍 b f s bfs bfs 从龙神开始找出所有可能告诉龙神消息的人,标记好,显然能告诉龙神消息的人都是不能传播的。
  • 第二遍 b f s bfs bfs 从小明开始找出小明到妹子最少经过多少个人,遇见被第一遍标记过的人则直接剪枝。

参考代码:

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<set>
#include<stack>
#include<queue>
#include<cstring>
#include<map>
#include<vector>
#define maxn 1000010
using namespace std;
 struct road{
 	int nxt,to;
 }E[3*maxn];
int n,k,vis[maxn],tim[maxn];
int main(){
	scanf("%d%d",&n,&k);
	memset(E,-1,sizeof(E));
	int now=n+1;
	for(int i=0;i<k;i++){
		int a,b;
		scanf("%d%d",&a,&b);
		E[now].nxt=E[a].nxt;
		E[now].to=b; 
		E[a].nxt=now++;
		E[now].nxt=E[b].nxt;
		E[now].to=a;
		E[b].nxt=now++;
	}
	queue<int>l;
	l.push(n-1);
	while(!l.empty()){
		int u=l.front();l.pop();
		for(int i=E[u].nxt;i!=-1;i=E[i].nxt){
			if(vis[E[i].to]||E[i].to==n||E[i].to==1)continue;
			vis[E[i].to]=1;
			l.push(E[i].to);
		}
	}
	l.push(1);
	tim[1]=-1;
	while(!l.empty()){
		int u=l.front();l.pop();
		for(int i=E[u].nxt;i!=-1;i=E[i].nxt){
			if(vis[E[i].to])continue;
			vis[E[i].to]=1;
			tim[E[i].to]=tim[u]+1;
			if(E[i].to==n){
				printf("%d\n",tim[E[i].to]);
				return 0;
			}
			l.push(E[i].to);
		}
	}
	printf("-1\n");
} 
H. 龙神的正义感

出题人: miamiao
AC/TOT: 9/65

题解: 使得一个图联通,可以考虑它的生成树,本题要求最大的 k k k 使得它联通,容易想到是一个图的最大生成树(这个喵神应该讲过?和最小生成树一样的!),因此我们直接对这个图求一遍最大生成树,这颗树最小的边就是答案!

参考代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000010;
typedef long long LL; 
struct node
{
	int u,v;
	LL w;
}a[maxn];
int sz = 1,fa[maxn];
bool cmp(const node &aa,const node &bb){return aa.w>bb.w;}
int tot ;
int find(int x)
{
	if(fa[x] == -1)return x;
	int r = fa[x];
	while(fa[r]!=-1)
	{
		fa[x] = fa[r];
		x = r;
		r = fa[x];
	}
	return fa[x];
}

void uni(int a,int b)
{
	
	int ra = find(a),rb = find(b);if(ra == rb)return;
	fa[rb] = ra;sz++;
}
int main(int argc, char const *argv[])
{
	memset(fa,-1,sizeof fa);
	int n,m;scanf("%d%d",&n,&m);
	for(int i = 1;i<= m;i++)scanf("%d%d%lld",&a[i].u,&a[i].v,&a[i].w);
	sort(a+1,a+1+m,cmp);
	for(int i = 1;i<= m;i++)
	{
		uni(a[i].u,a[i].v);
		if(sz == n){printf("%lld\n",a[i].w);return 0;}
	}
	printf("-1\n");
	return 0;
}
I. 龙神与甜甜圈

出题人: FSMM
AC/TOT: 18/109

题解: 考虑贪心地选择价格低的那次购买,如果第一次价格较低的甜甜圈个数小于 k k k 个,就尽量购买第一次与第二次价格差值小的甜甜圈。因此按照第一次与第二次价格的差值排序,差值相同按照编号排序,然后依次选取。唯一的trick是注意要使用long long

参考代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 200005
#define INF 0x3f3f3f3f
typedef long long ll;

using namespace std;

struct Ring
{
	ll x, y, z;
	int id;
}a[maxn];
bool cmp(Ring a, Ring b)
{
	if (a.z == b.z) return a.id < b.id;
	return a.z < b.z;
}
int main()
{
	int n, k, ans[maxn];

	scanf("%d%d", &n, &k);
	for (int i = 1; i <= n; i++) scanf("%I64d", &a[i].x);
	for (int i = 1; i <= n; i++) {
		scanf("%I64d", &a[i].y);
		a[i].z = a[i].x - a[i].y;
		a[i].id = i;
	}
	sort(a + 1, a + n + 1, cmp);
	int num = 0, cot = 0;
	ll sum = 0;
	for (int i = 1; i <= n; i++) {
		if (a[i].z <= 0 || num < k) {
			sum += a[i].x;
			num++;
			ans[++cot] = a[i].id;
		}
		else sum += a[i].y;
	}
	sort(ans + 1, ans + cot + 1);
	printf("%lld\n", sum);
	printf("%d\n", cot);
	for (int i = 1; i <= cot; i++)
		i == cot ? printf("%d\n", ans[i]) : printf("%d ", ans[i]);
	return 0;
}
J. 龙神与地下城

出题人: 阿尔西斯
AC/TOT: 0/61

题解: 不难看出是搜索题。每 k k k 秒会消失看似棘手,仔细分析每个点只有 k k k 种状态,不如假设第 i i i 秒真正有效的状态是 i % k i\%k i%k,我们可以考虑在 b f s bfs bfsvis[x][y]状态数组的基础上增加一个维度表示vis[x][y][z]其中 x , y x,y x,y 表示坐标 z z z 表示第 i i i 秒取模 k k k 的状态 i % k i\%k i%k ,接下来问题就转换成了简单的带障碍的2D搜索,大家都会做。

参考代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e2 + 5;
const int INF = 0x3f3f3f3f;
const int dx[] = {1, 0, -1, 0};
const int dy[] = {0, 1, 0, -1};

struct node{
	int x, y, step;
	node(int _x = 0, int _y = 0, int _step = 0){
		x = _x;
		y = _y;
		step = _step;
	}
};

queue<node> q;
char mp[maxn][maxn];
bool vis[maxn][maxn][52];

int main() {
	int n, m, k, sx, sy, T, i, j;
	scanf("%d", &T);
	while(T--){
		scanf("%d%d%d", &n, &m, &k);
		getchar();
		for(i=1;i<=n;i++){
			for(j=1;j<=m;j++){
				mp[i][j] = getchar();
				if(mp[i][j]=='S')
					sx = i, sy = j;
			}
			getchar();
		}
		
		int ans = INF;
		memset(vis, 0, sizeof(vis));
		while(!q.empty()) q.pop();
		q.push(node(sx, sy, 0));
		vis[sx][sy][0] = 1;
		while(!q.empty()){
			node tmp = q.front(); q.pop();
			if(mp[tmp.x][tmp.y]=='E'){
				ans = tmp.step;
				break;
			}
			for(i=0;i<4;i++){
				int x = tmp.x + dx[i], y = tmp.y + dy[i], stp = tmp.step+1;
				if(x<1 || x>n || y<1 || y>m || mp[x][y]=='#' || vis[x][y][stp%k]) continue;
				if(mp[x][y]=='*' && (stp%k)) continue;
				
				q.push(node(x, y, stp));
				vis[x][y][stp%k] = 1; 
			}
		}
		
		if(ans==INF) printf("-1\n");
		else printf("%d\n", ans);
	}
    return 0;
}
K. 这真的是签到题

出题人: strawberry
AC/TOT: 25/91

题解: 显然矩形越大则能采摘的草莓越多,观察后不难发现矩形一定是向样例这样的,两边分别取 x = 0 ,   y = 0 x=0,\ y=0 x=0, y=0,另外一个端点在直线上,也很容易证明如果点在区域内,显然有一个更优的解能将点扩展到直线上,因此我们直接枚举直线上的整点,暴力统计矩形内的整点就好了。枚举直线上的整点可以考虑枚举每一个整数 x x x ,再对每一个 y y y 求和,求和可以暴力求,复杂度 O ( b m ) O(bm) O(bm) ,当然单行的公式也很好推,大家可以尝试推一下,这样复杂度是 O ( b ) O(b) O(b)。还有一个拓展可以想想看:你能 O ( 1 ) O(1) O(1) 得出结果吗?

  • 唯一的trick就是需要使用64位整数,这个也在题目暗示明示了,很良心吧?

参考代码:

#include <bits/stdc++.h>
typedef long long ll;

int main()
{
	int m, b;
	scanf("%d%d", &m, &b);
	int x0 = m * b, y0 = b;
	ll ans = 0;
	for (int i = 0; i <= y0; i++)
	{
		int y_i = i;
		int x_i = m * (b - y_i);
		ll tmp = (1LL + x_i) * (y_i + 1) * x_i / 2 + (1LL + y_i) * (x_i + 1) * y_i / 2;
		ans = max(ans, tmp);
	//	printf("%lld : %d %d\n", tmp, x_i, y_i);
	}
	printf("%lld\n", ans);
	return 0;
}
冬训简单总结

很感谢一直坚持下来的各位同学,不管你们是对ACM充满着热情,还是抱着其他学习的目的,希望这个集训能有所收获,感受到算法带给大家的巨大魅力。出题人出的题不一定能完全反映出你的所有真实水平,但是我们希望每一次比赛你都有所成长和提高,善于分析总结自己的不足,这是在今后学习和生活的利器!也希望有兴趣的同学继续坚持下去,积极补题,查缺补漏,把冬训没做好的事情做得更加完美,下一轮积分赛等着大家,BITACM欢迎你的加入!

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值