Day 5

这篇博客探讨了两道编程竞赛题目,第一题利用数论中的等比数列求和公式解决,第二题通过并查集实现环路检测。文章深入浅出地解析了如何将数论知识应用于实际问题,并介绍了如何运用图论技巧检测环路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数论 并查集 树 数论?

A

Decription:
>**题目描述**

Sample Input:

5
6 6
7 7
8 8
9 9
10 1

Sample Output:

666666
7777777
88888888
1755646
112866758

思路:很显然从数据规模和这些诡异的数字轻松得知此题是数论,那么怎么做呢,首先我们要输出的结果是kkkkkk这个数,那么我们可以把它化成k*( 1 0 0 10^0 100+ 1 0 1 10^1 101+…+ 1 0 n 10^n 10n),那么很显然 赛时没看出来,可以用等比数列化简( S n S_n Sn= a 1 ( q n − 1 ) q − 1 \frac{a_1(q^n-1)}{q-1} q1a1(qn1) a 1 a_1 a1为首项,q为公比。然后用逆元mod一下下就好了。

代码

#include<iostream>
#include<cstdio> 
#include<cmath>
#define ll long long
using namespace std;
const ll mod=998244353;
ll n,k,ny,t;
ll ksm(ll x,ll y)
{
	ll res=1;
	while(y)
	{
		if(y&1) res*=x,res%=mod;
		x=x*x%mod,y>>=1;
	}
	return res;
}
int main()
{
	scanf("%lld",&t);
	ny=ksm(9,mod-2);
	while(t--)
	{
		scanf("%lld%lld",&n,&k);
		ll a1=ksm(10,n)-1;
	    printf("%lld\n",k*(a1*ny)%mod);
	}
	return 0;
} 

B

Decription:
>**题目描述**

Input

> **输入要求**

Output

> **输出要求**

Sample Input:

6 8 2
1 4
4 5
3 5
3 6
1 5
2 4
2 6
2 5

Sample Output:

3

Hint

> **输入样例**

思路
这题呀,可以看到,初一看缩点Tatjan,再一看似乎不用那么复杂,首先可以先把>k的编号先连上,再连<=k的编号,在此过程中用并查集去看两个点的父亲是否相同,如果是则是一个环,记录答案,不是就
连起来。

代码

#include<iostream>
#include<cstdio>
#define N 2000000
using namespace std;
int n,m,k,x[N+1],y[N+1],f[N+1],ans;
int fd(int xx)
{
	if(xx==f[xx]) return xx;
	return f[xx]=fd(f[xx]);
}
int qread()
{
	int x=0;
	char c=getchar();
	while(c>'9'||c<'0') c=getchar();
	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar(); 
	return x;
}
int main()
{
	n=qread(),m=qread(),k=qread();
	for(int i=1;i<=n;i++) f[i]=i;
	for(int i=1;i<=m;i++) 
	{
		x[i]=qread(),y[i]=qread();
		if(x[i]>k&&y[i]>k) f[fd(x[i])]=fd(y[i]);
	}
    for(int i=1;i<=m;i++)
	{
		if(x[i]<=k||y[i]<=k) 
		{
			if(fd(x[i])==fd(y[i])) ans++;
		    else f[fd(x[i])]=fd(y[i]);
		}
	 } 
	printf("%d",ans);
    return 0;	
} 

C

Decription:

一棵树删去任意条边,可以得到若干棵新树。
若使让每棵新树的节点数相同。问有多少种方法分割这棵树。
设给出的树的结点数为n,并给出n-1条边

Input

第一行一个正整数N,表示这棵树的结点总数。
接下来N-1行,每行两个数字X,Y表示编号为X的结点与编号为Y的结点相连。结点编号的范围为[1,N]。

Output

一个整数,表示方案数。注意,不砍去任何一条边也算作一种方案。

Sample Input:

输入样例

Sample Output:

6
1 2
2 3
2 4
4 5
5 6

Data Constraint

对于40%的数据,N ≤ 15
对于60%的数据,N ≤ 10^5
对于100%的数据,N ≤ 10^6
数据规模非常大,请使用高效的读入方式

思路
在这里插入图片描述
代码

#include<iostream>
#include<cstdio> 
#include<cmath>
#include<algorithm>
#define N 1000000
#define ll long long
using namespace std;
int n,x,y,con[N];
int he[N<<2],nxt[N<<2],cnt,to[N<<2],js1,js2,ans;
void add(int u,int v)
{
	cnt++;
	nxt[cnt]=he[u];
	he[u]=cnt;
	to[cnt]=v;
}
void build_tree(int pre,int now)
{
	for(int i=he[now];i;i=nxt[i])
	{
		int g=to[i];
		if(g==pre) continue;
		build_tree(now,g);
		con[now]+=con[g];
	}
	con[now]++;
}
int qread()
{
	char cc='o';
	int x=0,pd=1;
    while(cc>'9'||cc<'0') 
    {
      cc=getchar();
	  if(cc=='-') pd=-1;
	}
	while(cc<='9'&&cc>='0')
	{
	  x=(x<<3)+(x<<1)+cc-'0';
	  cc=getchar();	
	}
	return x*pd;
}
int main()
{
    n=qread();
    for(int i=1;i<=n-1;i++)
    {
    	x=qread(),y=qread();
		add(x,y),add(y,x); 
	}
	build_tree(0,1);
	for(int i=1;i<=sqrt(n);i++)
	{
		if(n%i==0)
		{
			js1=0,js2=0;
			for(int j=1;j<=n;j++)
				{
					if(con[j]%i==0) js1++;
					if(con[j]%(n/i)==0) js2++;
				}
            if(js1==n/i) ans++;
            if(js2==n/(n/i)) ans++;
            if(i==n/i) ans--;
		}
	}
	printf("%d",ans);
	return 0;
} 

D

Decription:

多个询问,
每个询问给出长度为n的2个序列a,b
每次可以对1<i<n的ai进行操作,
操作后, a i ′ = a i + 1 + a i − 1 − a i a^{'}_i=a_{i+1}+a_{i-1}-a_i ai=ai+1+ai1ai
问能否通过若干次操作,使得序列a变成 b

Input

给出询问数T
第一行一个正整数n
第二行给出序列a
第三行给出序列b

Output

是否能转变,输出Yes或者No,每个询问对应一行

Sample Input:

Sample Input 1
1
4
7 2 4 12
7 15 10 12
Sample Output 2
1
3
4 4 4
1 2 3

Sample Output:

Sample Output 1
Yes
Sample Output 2
No

Data Constraint

20%:2<=n<=10
100%:2<=n<=1e5,0<=ai,bi<=2e9,T<=10

思路:
赛时竟没看出来是道大水题??
在这里插入图片描述
代码

#include<iostream>
#include<cstdio> 
#include<cmath>
#include<algorithm>
#define N 100000
#define ll long long
using namespace std;
int t,n,a[N+1],c[N+1],b[N+1],d[N+1];
bool flag;
int qread()
{
	char cc='o';
	int x=0,pd=1;
    while(cc>'9'||cc<'0') 
    {
      cc=getchar();
	  if(cc=='-') pd=-1;
	}
	while(cc<='9'&&cc>='0')
	{
	  x=(x<<3)+(x<<1)+cc-'0';
	  cc=getchar();	
	}
	return x*pd;
}
int main()
{
	t=qread();
    while(t--)
    {
       flag=0;
       n=qread();
	   for(int i=1;i<=n;i++) a[i]=qread(),c[i]=a[i]-a[i-1];
	   for(int i=1;i<=n;i++) b[i]=qread(),d[i]=b[i]-b[i-1];
	   sort(c+1,c+n+1);
	   sort(d+1,d+n+1);
	   for(int i=1;i<=n;i++)
	    {
	   	  if(c[i]!=d[i]) 
	   	    {
	   	  	    flag=1;
	   	  	    break;
			}
		} 
		if(flag) putchar('N'),putchar('o');
		else putchar('Y'),putchar('e'),putchar('s');
		putchar('\n');
	}
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值