zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 50

    Educational Codeforces Round 50

    codeforces

    G. Sources and Sinks

    description

    有一张(DAG),定义source为入度为零的点,sink为出度为零的点。保证source和sink的个数相等且不超过(20) 。定义匹配一个source和一个sink为从sink向source连一条有向边。问是否任意一个source与sink之间的完美匹配都可以使原图变成强连通。

    (nle10^6)

    solution

    设source与sink各有(C)个,那么只需要保证这(2C)个点组成的图强连通就行了。

    有一个结论是:对于任意一个source的集合(S)(|S| eq0,|S| eq C) ,它能到达的sink集合是(f(S)) ,则需要有(|S|>|f(S)|)

    复杂度(O(C(n+m)+C2^C))

    code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    using namespace std;
    int gi(){
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    const int N = 1e6+5;
    int n,m,cnt[N<<1],to[N],nxt[N],head[N],in[N],val[N],C,vis[N],ans[20];
    int dfs(int u){
    	vis[u]=1;int res=val[u];
    	for (int e=head[u];e;e=nxt[e])
    		if (!vis[to[e]]) res|=dfs(to[e]);
    	return res;
    }
    int main(){
    	n=gi();m=gi();
    	for (int i=1;i<=m;++i){
    		int u=gi(),v=gi();
    		to[i]=v;nxt[i]=head[u];head[u]=i;++in[v];
    	}
    	for (int i=1;i<=n;++i) if (!head[i]) val[i]=1<<C++;
    	for (int i=1,j=0;j<C;++i) if (!in[i]) memset(vis,0,sizeof(vis)),ans[j++]=dfs(i);
    	for (int i=0;i<(1<<C);++i) cnt[i]=cnt[i>>1]+(i&1);
    	for (int i=1;i<(1<<C)-1;++i){
    		int res=0;
    		for (int j=0;j<C;++j) if (i>>j&1) res|=ans[j];
    		if (cnt[i]>=cnt[res]) return puts("NO"),0;
    	}
    	return puts("YES"),0;
    }
    

    F. Relatively Prime Powers

    description

    将一个数质因数分解为(p_1^{a_1}p_2^{a_2}...p_k^{a_k}) ,定义其是elegent当且仅当(gcd(a_1,a_2...a_k)=1)

    (T)组询问,每次询问(2-n)中elegent的数的个数。

    (Tle10^5,nle10^{18})

    solution

    首先莫比乌斯随便演一下答案就是(sum_{i=1}^{infty}mu(i)(sqrt[i]n-1))

    直接算的话复杂度(O(Tlog^2n))(每个质因子二分根号的那个值)可能过不了。

    把询问离线,从大到小做,可以省去一个二分。

    复杂度(O(Tlog T+Tlog n))

    code

    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define ll long long
    const int N = 1e5+5;
    struct node{
    	ll x;int y;
    	bool operator < (const node &b) const
    		{return x>b.x;}
    }a[N];
    int mu[61]={0,1,-1,-1,0,-1,1,-1,0,0,1,-1,0,-1,1,1,0,-1,0,-1,0,1,1,-1,0,0,1,0,0,-1,-1,-1,0,1,1,1,0,-1,1,1,0,-1,-1,-1,0,0,1,-1,0,0,0,1,0,-1,0,1,0,1,1,-1,0};
    ll mx[61]={0,0,0,1000000,31623,3982,1000,373,178,100,67,46,33,25,20,16,13,11,10,9,8,7,6,6,5,5,5,4,4,4,4,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
    int n;ll now[61],ans[N];
    ll fastpow(ll a,int b){
    	ll res=1;
    	while (b) {if (b&1) res*=a;a*=a;b>>=1;}
    	return res;
    }
    int main(){
    	scanf("%d",&n);
    	for (int i=1;i<=n;++i) scanf("%I64d",&a[i].x),a[i].y=i;
    	sort(a+1,a+n+1);
    	for (int i=3;i<=60;++i) now[i]=fastpow(mx[i],i);
    	for (int i=1;i<=n;++i){
    		mx[1]=a[i].x;mx[2]=sqrt(a[i].x);
    		for (int j=3;j<=60;++j)
    			while (now[j]>a[i].x) --mx[j],now[j]=fastpow(mx[j],j);
    		for (int j=1;j<=60;++j) ans[a[i].y]+=1ll*(mx[j]-1)*mu[j];
    	}
    	for (int i=1;i<=n;++i) printf("%I64d
    ",ans[i]);
    	return 0;
    }
    

    E. Covered Points

    description

    给你(n)条线段,问你有多少个点被这些线段覆盖了。

    (nle1000,)坐标范围(le10^6)

    solution

    先不考虑算重,那么一条直线的贡献是(gcd(|x_1-x_2|,|y_1-y_2|)+1)

    然后因为两条不重合直线至多一个交点,所以可以直接解出来交点,然后判重即可。

    算交点直接联立两个一般式解方程,一般式用两点式求。

    复杂度(O(n^2log n))

    code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int gi(){
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    #define ll long long
    const int N = 1005;
    struct seg{
    	int x1,y1,x2,y2;
    	int cal(){
    		return __gcd(abs(x2-x1),abs(y2-y1))+1;
    	}
    	bool in(int x,int y){
    		bool fg=1;
    		if (x1<=x2) fg&=(x1<=x&&x<=x2);
    		else fg&=(x2<=x&&x<=x1);
    		if (y1<=y2) fg&=(y1<=y&&y<=y2);
    		else fg&=(y2<=y&&y<=y1);
    		return fg;
    	}
    }l[N];
    int n,len,ans;pair<int,int>o[N];
    struct line{
    	ll A,B,C;
    	line(){}
    	line(seg a){
    		A=a.y2-a.y1;B=a.x1-a.x2;
    		C=-A*a.x1-B*a.y1;
    	}
    };
    bool cross(int i,int j,int &X,int &Y){
    	line a(l[i]),b(l[j]);
    	ll x=a.B*b.C-a.C*b.B,y=-a.A*b.C+a.C*b.A,z=a.A*b.B-a.B*b.A;
    	if (!z) return false;if (x%z||y%z) return false;
    	X=x/z;Y=y/z;
    	if (l[i].in(X,Y)&&l[j].in(X,Y)) return true;return false;
    }
    int main(){
    	n=gi();
    	for (int i=1;i<=n;++i){
    		l[i]=(seg){gi(),gi(),gi(),gi()};
    		ans+=l[i].cal();len=0;
    		for (int j=1,x,y;j<i;++j)
    			if (cross(i,j,x,y)) o[++len]=make_pair(x,y);
    		sort(o+1,o+len+1);len=unique(o+1,o+len+1)-o-1;ans-=len;
    	}
    	printf("%d
    ",ans);return 0;
    }
    

    D. Vasya and Arrays

    description

    给你两个数组(A,B) ,你的每次操作是可以把连续一段数合在一起,值为这些数的和。

    求把两个数组变成相同后数组的最长长度。

    (nle3 imes10^5,1le a_i,b_ile10^9)

    solution

    贪心,每次用双指针找到两个数组最短的相等前缀。复杂度线性。

    code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int gi(){
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    const int N = 3e5+5;
    int a[N],b[N];
    int main(){
    	int n=gi(),i,j,ans=0;
    	for (i=1;i<=n;++i) a[i]=gi();
    	int m=gi();
    	for (i=1;i<=m;++i) b[i]=gi();
    	long long sa=a[1],sb=b[1];
    	for (i=1,j=1;i<=n&&j<=m;){
    		if (sa==sb) ++ans,sa=a[++i],sb=b[++j];
    		else if (sa>sb) sb+=b[++j];
    		else sa+=a[++i];
    	}
    	while (i<n) sa+=a[++i];
    	while (j<m) sb+=b[++j];
    	if (sa==sb) printf("%d
    ",ans);
    	else puts("-1");
    	return 0;
    }
    

    C. Classy Numbers

    description

    定义一个数是classy的当且仅当其在十进制表示下至多有(3)个非零位。

    (T)组询问,每次问([L_i,R_i])之间有多少个classy的数。

    (Tle10^4,L_i,R_ile10^18)

    solution

    可以直接数位dp。

    我比较懒,用了另一种方法:拿组合数算一下会发现满足条件的数只有60w+个,所以就爆搜出来再二分就行了。

    code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define ll long long
    ll o[1000005],L,R;int T,len;
    void dfs(int i,int j,ll sum){
    	if (i==18) {o[++len]=sum;return;}
    	dfs(i+1,j,sum*10);
    	if (j<3)
    		for (int k=1;k<=9;++k)
    			dfs(i+1,j+1,sum*10+k);
    }
    int main(){
    	dfs(0,0,0);o[++len]=1e18;
    	scanf("%d",&T);while (T--){
    		scanf("%I64d%I64d",&L,&R);
    		printf("%d
    ",upper_bound(o+1,o+len+1,R)-lower_bound(o+1,o+len+1,L));
    	}
    	return 0;
    }
    

    B. Diagonal Walking v.2

    description

    (q)组询问,每次从((0,0))点出发走向((n,m)),每一步可以走到横纵坐标(pm1)的位置(不能不走,也就是有(8)种走法)要求恰好走(k)步,求最多可以斜着走多少步。

    (qle10^4,n,m,kle10^{18})

    solution

    走法大体上分成两个阶段(假设(n>m)):第一阶段横着走到((n-m,0)),当然这里的横着走指的是一上一下,即在走了偶数步后结果上还是横着走的;第二阶段斜着走到((n,m))

    步数可能会多,多余的偶数步可以在终点消耗掉,并且都可以算贡献。现在只需要考虑怎么消耗掉一步:

    如果要在第一阶段消耗掉一步,必须要(n-m)是奇数,这样等效于把起点移到((1,0)) ,同时步数减(1)

    如果要在第二阶段消耗掉一步,必须要(n-k)是奇数,这样等效于把起点移到((1,1)) ,同时步数减(2)

    所以优先在第一阶段消耗掉这一步,这样的话答案就是(k)了。

    code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define ll long long
    ll gi(){
    	ll x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    int main(){
    	int q=gi();while (q--){
    		ll x=gi(),y=gi(),k=gi();if (x<y) swap(x,y);
    		if ((x&1)^(y&1)) --k,--x;
    		else if ((x&1)^(k&1)) k-=2,--x,--y;
    		printf("%I64d
    ",k<x?-1:k);
    	}
    	return 0;
    }
    

    A. Function Height

    description&solution

    输出(lceilfrac nk ceil)

    code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int main(){
    	long long n,k;
    	scanf("%I64d%I64d",&n,&k);
    	printf("%I64d
    ",(k+n-1)/n);
    	return 0;
    }
    
  • 相关阅读:
    查看Mysql版本
    Day03_SpringCloud2
    Day01_SpringBoot
    【Java面试题】如何判断一个字符串中某个字符出现的次数?
    你以为这样写Java代码很6,但我看不懂
    smart-socket实战:玩转心跳消息
    JVM 对象分配过程
    Spring Cloud基于Redis实现的分布式锁
    Python10行以内代码能有什么高端操作
    会话技术之Cookie详解
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9651368.html
Copyright © 2011-2022 走看看