其他分享
首页 > 其他分享> > Codeforces Round #202 (Div. 1)

Codeforces Round #202 (Div. 1)

作者:互联网

首先肯定是先找到最大的ai为maxx 答案起码是maxx

发现如果我们按照从大到小依次摆放 只要maxx*(n-1)能容下Σai 那一定能满足(自行模拟一下就好,顺序一定是从大到小)

所以我们只要不断使maxx++ 直到maxx*(n-1)>=Σai就好

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int maxn=1e5+5;
ll n,ans;
ll tot,a[maxn];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i],tot+=a[i],ans=max(a[i],ans);
	while(1){
		if(ans*(n-1)>=tot){
			cout<<ans;
			return 0;
		}else ans++;
	}
     return 0;
}

这个题看似很简单 确实可以很简单 但是确实也可以难倒人 我就是

开始我的思路一直是从下往上走 却发现根本行不通 索性换个思路 从上往下

假设整棵树的苹果总数为x,我们假设根节点有n棵子树,那么分给每棵子树的苹果数为x/n,并且x一定是n的倍数

利用递归,将子树的苹果平均分给子树的子树。。。

一直到叶子节点,此时我们可以知道,该叶子节点分到的苹果为x的k分之一,因此x为k的倍数,并且x/k不大于该叶子的原来的苹果数

根据这个,我们可以得到一个最小的x; 但要保证x能够均分给每个子树 怎么办?减去 x%所有的lcm 就好

另外,为了避免倍数累乘的时候溢出,当发现k>x时,易知只能将所有的苹果都移掉,直接输出即可。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
using namespace std;
#define MAXN 100010
typedef long long ll;
int n;
int num[MAXN];
vector<int> G[MAXN];
ll x,sum=0,lcm=1;
ll gcd(ll a,ll b)
{
    return b==0 ? a : gcd(b, a%b);
}

void dfs(int cur=1, ll div=1LL, int fa=-1)
{
    if(div>x)
    {
        cout<<sum;
        exit(0);
        return;
    }
    if(num[cur] || G[cur].size()<=1 && cur!=1) // 是叶子节点
    {
        x=min(x, num[cur]*div);
        lcm=div*lcm/gcd(lcm,div);
        return;
    }
    for(int i=0; i<G[cur].size(); i++)
    {
        if(G[cur][i]!=fa)
            dfs(G[cur][i], div*(ll)(G[cur].size()-1*(cur!=1)),cur);
    }
}
int main()
{
    //freopen("in.txt","r", stdin);

    cin>>n;
    for(int i=1; i<=n; i++)
    {
        scanf("%d", &num[i]);
        sum+=(ll)num[i];
    }
    x=sum;
    for(int i=1; i<=n-1; i++)
    {
        int u,v;
        scanf("%d %d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs();
    cout<<sum-(x-x%lcm);

    return 0;
}

题目还是很好明白 但是思来想去就是想不明白用什么数据结构维护

这个题目思路特别好

为什么要考虑分块?首先想不到合适的数据结构只有暴力

现在有两个问题

1.考虑该集合对其他集合造成的影响

2.该集合当前的Σ是多少

分块的好处在于 考虑 大集合:集合大小 > √集合总数 的集合个数 < √集合总数

              小集合:集合大小 < √集合总数 的集合大小 < √集合总数

这样我们分别对 大集合进行操作1 和 小集合进行操作2 时间复杂度就能保证

不得不说这个题目思路真的好牛

//Subset Sums
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long lint;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||'9'<ch) {if(ch=='-') f=-1; ch=getchar();}
    while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int const N=1e5+1e3;
int const N0=400;
int n,m,q,n0; lint a[N];
int ori[N];
struct _set{int siz,id; vector<int> x;} s[N];
bool cmpSiz(_set x,_set y) {return x.siz>y.siz;}
bool tmp[N]; int cnt[N0][N]; lint add[N0],sum[N0];
int main()
{
    n=read(),m=read(),q=read();
    for(int i=1;i<=n;i++) a[i]=read();
    int sumK=0;
    for(int i=1;i<=m;i++)
    {
        s[i].siz=read(),s[i].id=i,s[i].x.push_back(0); sumK+=s[i].siz;
        for(int p=1;p<=s[i].siz;p++) s[i].x.push_back(read());
    }
    sort(s+1,s+m+1,cmpSiz);
    for(int i=1;i<=m;i++) ori[s[i].id]=i;
    n0=sqrt(sumK); int cnt1=0;
    for(int i=1;s[i].siz>=n0;i++) cnt1=i;
    for(int i=1;i<=cnt1;i++)
    {
        memset(tmp,false,sizeof tmp);
        for(int p=1;p<=s[i].siz;p++) sum[i]+=a[s[i].x[p]],tmp[s[i].x[p]]=true;
        for(int j=1;j<=m;j++)
            for(int p=1;p<=s[j].siz;p++) if(tmp[s[j].x[p]]) cnt[i][j]++;
    }
    for(int owo=1;owo<=q;owo++)
    {
        char opt; scanf("%c",&opt);
        if(opt=='?')
        {
            int k=ori[read()];
            if(k<=cnt1) printf("%lld\n",sum[k]);
            else
            {
                lint res=0;
                for(int p=1;p<=s[k].siz;p++) res+=a[s[k].x[p]];
                for(int i=1;i<=cnt1;i++) res+=add[i]*cnt[i][k];
                printf("%lld\n",res);
            }
        }
        if(opt=='+')
        {
            int k=ori[read()]; lint v=read();
            if(k<=cnt1) add[k]+=v;
            else for(int p=1;p<=s[k].siz;p++) a[s[k].x[p]]+=v;
            for(int i=1;i<=cnt1;i++) sum[i]+=v*cnt[i][k];
        }
    }
    return 0;
}

经典的LGV定理 考虑起点为 (1,2)和(2,1) 终点为(n-1,m) 和 (n,m-1)

最后大数据读入要用scanf 我用cin超时了!!!!

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int maxn=3e3+5;
const int mod=1e9+7;
int n,m;
ll dp[maxn][maxn][2];
char c[maxn][maxn]; 
int main(){
	cin>>n>>m;
	dp[2][1][0]=dp[1][2][1]=1;
	for(int i=1;i<=n;i++)
	scanf("%s",c[i]+1);
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++){
		if(c[i][j]=='#')continue;
	if(c[i][j-1]=='.'){
		dp[i][j][0]=(dp[i][j][0]+dp[i][j-1][0])%mod;
	    if(j-1>=2)
	    dp[i][j][1]=(dp[i][j][1]+dp[i][j-1][1])%mod;
	}
	if(c[i-1][j]=='.'){
		dp[i][j][1]=(dp[i][j][1]+dp[i-1][j][1])%mod;
		if(i-1>=2)
		dp[i][j][0]=(dp[i][j][0]+dp[i-1][j][0])%mod;
	}
	}
	cout<<(dp[n][m-1][0]*dp[n-1][m][1]%mod+mod-dp[n-1][m][0]*dp[n][m-1][1]%mod)%mod<<endl;
     return 0;
}

标签:202,int,ll,Codeforces,long,集合,Div,include,dp
来源: https://www.cnblogs.com/wzxbeliever/p/16196310.html