zoukankan      html  css  js  c++  java
  • AtCoder Beginner Contest 133

    AtCoder Beginner Contest 133

    Time:7/7(Sun) 20:00

    WebsiteAtCoder BC-133

    C

    题目描述:

    给定区间[l,r],请你求出f(i,j)=i*j%2019 (l<=i<j<=r)的最小值。

    数据范围:

    0<=l,r<=(2*10^9)

    题解:

    由于数据范围很大,一开始觉得暴力枚举是不可能的了,然后就找规律,以为和2019的什么性质有关。

    后来突然发现,只要r-l>=2019,那么在这之中必定存在2019的倍数,答案就为0。反之,r-l<2019,直接暴力枚举就好了。haosaoa

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll l,r;
    int main(){
    	scanf("%lld %lld",&l,&r);
    	if(r-l>=2019){puts("0");return 0;}
    	ll ma=2019;
    	for(ll i=l;i<=r;i++)
    		for(ll j=i+1;j<=r;j++)
    			if(i*j%2019<ma)ma=i*j%2019;
    	printf("%lld",ma);
    }
    

    D

    题目描述:

    有n座山(n为奇数),编号1..n,构成一个环,每两座山之间有一个水坝,当下雨时,如果某座山收集到x的水(x为偶数),则这些水会平分地流入两旁的水坝。现在已知第i座水坝收集到的水为(a_i),请求出一开始每座山收集到的雨水量。题目保证对于每组给定的数据,存在且仅存在一组可行解。

    数据范围:
    Constraints

    All values in input are integers.
    3≤N≤(10^5-1)
    N is an odd number.
    0≤(A_i)(10^9)
    The situation represented by input can occur when each of the mountains receives a non-negative even number of liters of rain.

    样例:

    输入样例

    5
    3 8 7 5 5
    

    输出样例

    2 4 12 2 8
    
    题解:

    根据题意建立模型,设原来每座大山收集到的雨量为(x_i)

    易知$$frac{x1}{2}+frac{x2}{2}=A_1$$
    将等式同乘以2,即预处理时,将(A_i)乘上2。

    然后得到下面式子:这是n=5的情况

    [left{ egin{array}{c} x1+x2=A1……①\ x2+x3=A2……②\ x3+x4=A3……③\ x4+x5=A4……④\ x5+x1=A5……⑤\ end{array} ight. ]

    发现这很小学奥数题,所以试着消元,将全部式子累加除2,得到(x_1+..x_n),再将①+③得到,(x_1+..x_{n-1}),两式作差,得到(x_n),然后依次解出其他方程。

    注意,这种方法只适用于n为奇数的情况。而题目给定的n必定为奇数,所以这种方法对于此题完全适用。Code 1是这种消元方法的代码。而Code 2不受n的奇偶性限制,更具扩展性。

    //Code 1
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n;
    ll a[100009],b[100009],sum;
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)scanf("%lld",&a[i]),a[i]*=2;
    	for(int i=1;i<=n;i++)sum+=a[i];
    	sum/=2;
    	ll pre=0;
    	for(int i=1;i<n;i+=2)pre+=a[i];
    	ll tmp=sum-pre;
    	b[n]=tmp,b[1]=a[n]-tmp;
    	for(int i=2;i<=n-1;i++)b[i]=a[i-1]-b[i-1];
    	for(int i=1;i<=n;i++)printf("%lld ",b[i]);
    }
    

    依然是由上面那个方程组推来,这次我们将n设为偶数4

    (x1+x2=A1) ( ightarrow) (x2=A1-x1)

    相应的:(x3=A2-x2=A2-A1+x1)

    (x4=A3-x3=A3-A2+A1-x1)

    (x1=A4-x4=A4-A3+A2-A1+x1)

    发现最后一条式子又迭代回了(x1),变成了易解的一元一次方程,由此,模拟这个迭代的过程,设前面一坨A的式子为a,b为方程式右边(x1)的系数,然后不断迭代就可以求出(x1)了。

    //Code 2
    #include<bits/stdc++.h>
    #define LL long long
    #define M 1000005 
    using namespace std;
    const int P=1e9+7; 
    int  A[M];
    int main(){
    	int n,m;
    	cin>>n;
    	for(int i=1;i<=n;i++)scanf("%d",&A[i]),A[i]<<=1;
    	LL a=A[1],b=-1;
    	for(int i=2;i<n;i++){
    		a=A[i]-a;
    		b*=-1;
    	}
    	LL x1=(A[n]-a)/(b+1);
    	printf("%lld",x1);
    	for(int i=1;i<n;i++){
    		x1=A[i]-x1;
    		printf(" %lld",x1);
    	}
    	puts("");
    	return 0;
    }
    

    E

    题目描述:

    给定一棵n个节点的树,由n-1条边构成,第i条边连接节点(u_i)(v_i)。现在一共有k中颜色的染料,请你对这棵树的每一个节点进行染色,并满足下述条件:

    • 对于树上的任意两个节点(u,v),若它们间的距离小于等于2,则这两个节点所染的颜色必须不同。

    请你求出可行的染色方案数。 由于答案可能较大,请输出答案%1 000 000 007后的结果。

    数据范围&输入输出格式:
    Constraints

    1≤N,K≤(10^5)
    1≤(a_i,b_i)≤N
    The given graph is a tree.

    输入第一行两个整数n,k。接下来的n-1行每行读入两个整数u,v,表示节点u,v间存在一条边。

    输出一行,包含一个整数,意义见题面。

    样例:

    输入:

    5 4
    1 2
    1 3
    1 4
    4 5
    

    输出:

    48
    
    题解:

    看数据范围,显然正解应该是O(N)的。如果颜色是3种的话可以直接树形Dp,O(N)得到。然而有k种颜色——组合数?显然可以——详见xiaoC代码,但是会很麻烦。我们试着将每一个节点单独处理出来,即利用乘法原理,单独统计每个节点对答案的贡献。

    观察一下样例,发现,对于任意节点x,假设它旁边什么节点都没有(显然这是不可能的),那它有k种染色方案,如果他有父亲节点(fa[x]!=0),则k要-1,如果他还有祖父节点(fa[fa[x]]!=0),则k要再-1。如果他有num个兄弟节点(包括x自己),则k要减去(num-1)。那么最后将每个节点的方案数都乘起来——这就是答案吗?,发现连样例都过不了,因为我们这样统计单个节点x的时候,是在他距离为2之内的节点的颜色状态都确定下的情况,这样乘起来并没有考虑颜色的排列情况,故对于每组“一排儿子“还要乘以(num!),即颜色的排列情况。

    但是仔细分析,完全不用那样搞,我们可以以某个节点x的所有儿子为一个单位进行统计,并计算对答案的贡献,其实本质与上面那个方法是一模一样的,只是将一组儿子一起统计,思路会更为清晰。

    设节点x的儿子数位son[x],统计详见下面的伪代码,注意,既然x有儿子,则必然存在fa[son[x]],虽然废话,所以下面统计时是从k-s-1开始的。

    For(x:=1 to n){

    s=0;

    If(x存在fa[x])s++;

    ans*=(k-s-1)*(k-s-2)*....(k-s-son[x])

    }

    完整代码如下,记得当ans<=0时要输出0,即不存在可行的方案——至于为什么会存在ans<=0的情况,由上面统计过程就可知道。

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long 
    const ll mod=1000000007;
    const int N=1e5+5;
    int d[N],son[N],fa[N],n,k;
    ll ans=1;
    vector<int>e[N];
    int dfs(int x,int f){
    	fa[x]=f;
    	for(int i=0;i<e[x].size();i++){
    		int y=e[x][i];
    		if(y==f)continue;
    		son[x]++;
    		dfs(y,x);
    	}
    }
    int main(){
    	n=read(),k=read();
    	for(int i=1,u,v;i<n;i++){
    		u=read(),v=read();
    		e[u].push_back(v);
    		e[v].push_back(u);
    	}
    	dfs(1,0);
    	for(int i=1;i<=n;i++){
    		int s=0;
    		if(fa[i])s++;
    		for(int j=1;j<=son[i];j++)ans=(ans*1ll*(k-j-s))%mod;
    	}
    	ans=ans*1ll*k;
    	if(ans<=0)puts("0");
    	else printf("%lld",ans%mod);
    }
    

    F

    题目描述:

    依然是一棵n个节点的树,n-1条边构成,第i条边连接节点(a_i,b_i),且这条边颜色为(c_i),长度为(d_i)。每条边的颜色c为1~(n-1)的一个整数,且不同的数字代表不同的颜色,相同的颜色必定由相同的数字表示( 翻译自原题,其实是废话)。

    现在给定m个查询操作Q

    • Q x y u v,表示若将所有颜色为x的边的长度改成y,那么节点u,v间的距离为多少?注意,只是假设,并不影响实际长度,也不影响后面的询问。
    数据范围&输入输出格式
    Constraints

    2≤N≤(10^5)

    1≤Q≤(10^5)

    1≤(a_i,b_i)≤N

    1≤(c_i)≤N−1

    1≤(d_i)(10^4)

    1≤(x_j)≤N−1

    1≤(y_j)(10^4)

    1≤(u_j)<(v_j)≤N

    • The given graph is a tree.
    • All values in input are integers.

    输入,第一行包括两个整数n,q分别表示节点个数,询问个数;
    之后的n-1行每行四个整数,描述树上的一条边;
    最后q行每行四个整数x,y,u,v表示一个询问。

    输出,对于每一个询问打印答案,每个一行。

    样例:

    输入:

    5 3
    1 2 1 10
    1 3 2 20
    2 4 4 30
    5 2 1 40
    1 100 1 4
    1 100 1 5
    3 1000 3 4
    

    输出:

    130
    200
    60
    
    题解:

    查询树上两点距离——用LCA,但是每一次询问,距离都会改变,所以不能这样搞。看到n 1e5的数据范围,硬上修改肯定也不行。

    关注到询问的一个特性——每次修改都是暂时的,不会影响到后面,这暗示我们每个询问都是独立的!独立的?——那就把每个询问放在树上,离线处理!

    怎么放呢,联想普通的求两点间距离,即dis(u,v)=dis(u)+dis(v)-2*dis(lca),又发现这三个节点——u,v,lca,对于答案的贡献都是单独的!所以,我们可以把询问拆成三份,分别放在这三个节点上,记录{i(第几个询问),co(要改的颜色),d(要改成的长度),k(属性——为下面的树上差分做准备)}。然后离线处理每个询问。

    如何处理?显然O(N)跑一遍整棵树,定义状态(x,f,D)——当前节点为x,父亲节点为f,从树根到这走了D长度。先处理这个节点上的询问,

    [ret[now.id]+=now.k*(D-dis[now.co]+cnt[now.co]*now.d); ]

    其实上面这个式子就是在利用树上差分统计答案,这样就可以独立每个节点对询问的贡献了。完整代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+5;
    int n,m;
    int fa[N][20],dep[N];
    int dis[N],cnt[N],ret[N];
    struct node{int u,co,l;};
    vector<node>e[N];
    struct ques{int id,co,d,k;};
    vector<ques>q[N];
    inline int read(){
        int x=0;char c=getchar();
        while(c<'0'||c>'9')c=getchar();
        while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
        return x;
    }
    void pre(int x,int f){
    	fa[x][0]=f,dep[x]=dep[f]+1;
    	for(int i=0;i<e[x].size();i++)
    		if(e[x][i].u!=f)pre(e[x][i].u,x);
    }
    int UP(int x,int step){
        for(int i=0;i<=17;i++)if(step&(1<<i))x=fa[x][i];
        return x;
    }
    int LCA(int a,int b){
        if(dep[a]>dep[b])swap(a,b);
        b=UP(b,dep[b]-dep[a]);
        if(a==b)return a;
        for(int i=17;i>=0;i--)
            if(fa[a][i]!=fa[b][i])a=fa[a][i],b=fa[b][i];
        return fa[a][0];
    }
    void dfs(int x,int f,int D){
    	for(int i=0;i<q[x].size();i++){
    		ques now=q[x][i];
    		ret[now.id]+=now.k*(D-dis[now.co]+cnt[now.co]*now.d);
    	}
    	for(int i=0;i<e[x].size();i++){
    		node y=e[x][i];
    		if(y.u==f)continue;
    		cnt[y.co]++,dis[y.co]+=y.l;
    		dfs(y.u,x,D+(y.l));
    		cnt[y.co]--,dis[y.co]-=y.l;
    	}
    }
    int main(){
        n=read(),m=read();
        for(int i=1,a,b,c,d;i<n;i++){
            a=read(),b=read(),c=read(),d=read();
            e[a].push_back((node){b,c,d});
            e[b].push_back((node){a,c,d});
        }
        
    	pre(1,0);
        for(int i=1;i<=17;i++)
            for(int j=1;j<=n;j++)fa[j][i]=fa[fa[j][i-1]][i-1];	
            
        for(int i=1,u,v,c,d;i<=m;i++){
           c=read(),d=read(),u=read(),v=read();
           q[u].push_back((ques){i,c,d,1});
           q[v].push_back((ques){i,c,d,1});
           q[LCA(u,v)].push_back((ques){i,c,d,-2});
        }
    	dfs(1,0,0);
    	
        for(int i=1;i<=m;i++)printf("%d
    ",ret[i]);
    } 
    
    long live freedom!
  • 相关阅读:
    [LeetCode] Output Contest Matches 输出比赛匹配对
    [LeetCode] 527. Word Abbreviation 单词缩写
    [LeetCode] Permutation in String 字符串中的全排列
    [LeetCode] 560. Subarray Sum Equals K 子数组和为K
    [LeetCode] Reshape the Matrix 重塑矩阵
    [LeetCode] 536. Construct Binary Tree from String 从字符串创建二叉树
    [LeetCode] IPO 上市
    [LeetCode] Binary Tree Tilt 二叉树的坡度
    [LeetCode] Array Partition I 数组分割之一
    [LeetCode] Zuma Game 祖玛游戏
  • 原文地址:https://www.cnblogs.com/Tieechal/p/11185912.html
Copyright © 2011-2022 走看看