A.小竹与妈妈

#include<cstring>
#include<algorithm>
using namespace std;
int main()
{
	int a,b,x;
	cin>>a>>b>>x;
	
	cout<<(x-b)/a<<endl;
	return 0;
} 

B.走丢的小竹

#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int N=1e5+10;
vector<int> points[N];
int n,m,q;

int main()
{
	cin>>n>>m>>q;
	
	for(int i=1;i <= n;i++)
	{
        int x;
		cin>>x;
		points[x].push_back(i);
	}
	
	while(q--)
	{
		int x;
		cin>>x;
		
		printf("%d\n",n-points[x].size());
	}
	
	return 0;
}

C.小竹关禁闭

方法一:状态表示:f[i]表示只考虑前i个物品,且选上第i个物品最大长度. 当i <= k+1时f[i]=a[i],当i > k+1时f[i]=max(f[i],f[j]+a[i]),其中j从1到第i-k-1. 时间复杂度o(n*n)

#include<algorithm>
#include<cstring>
using namespace std;
const int N=4010;
int a[N],f[N];
int n,k;

int main()
{
	cin>>n>>k;
	
	for(int i=1;i <= n;i++) cin>>a[i];
	
	for(int i=1;i <= n;i++)
	{
		if(i <= k+1) f[i]=a[i];
		else 
        {
            for(int j=1;j <= i-k-1;j++)
                f[i]=max(f[i],f[j]+a[i]);
        }
	}
	
    int res=0;
    for(int i=1;i <= n;i++) res=max(res,f[i]);
    
	cout<<res<<endl;
	return 0;
} 

方法一:状态表示:f[i]表示只考虑前i个物品的最大长度. 此时第i个物品可选可不选两种情况 时间复杂度o(n)

#include<algorithm>
#include<cstring>
using namespace std;
const int N=4010;
int a[N],f[N];
int n,k;

int main()
{
	cin>>n>>k;
	
	for(int i=1;i <= n;i++) cin>>a[i];
	
	for(int i=1;i <= n;i++)
	{
		if(i < k+1) f[i]=max(f[i-1],a[i]);
		else f[i]=max(f[i-k-1]+a[i],f[i-1]);
	}
	
	cout<<f[n]<<endl;
	return 0;
} 

D.游戏购买!

两遍bfs 时间复杂度:O(n*m)

#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
typedef pair<int,int> PII;
#define x first
#define y second
const int N=2010;
int w[N][N];
vector<PII> legal;
int n,m,x;
int sx,sy,ex,ey;

void bfs(int sx1,int sy1,int d[][N])
{
	PII q[N*N];
	int hh=0,tt=-1;
	q[++tt]={sx1,sy1};
	d[sx1][sy1]=0;
	
	int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
	
	while(hh <= tt)
	{
		PII t=q[hh++];
		
		for(int i=0;i < 4;i++)
		{
			int x=t.x+dx[i],y=t.y+dy[i];
			if(x < 0 || x >= n || y < 0 || y >= m) continue;
			if(d[x][y] != -1) continue;
			if(w[x][y] == -1) continue;
			q[++tt]={x,y};
			d[x][y]=d[t.x][t.y]+1;
		}
	}
}

int main()
{
	cin>>n>>m>>x;

	cin>>sx>>sy>>ex>>ey;
	sx--,sy--,ex--,ey--;
	
	for(int i=0;i < n;i++)
	for(int j=0;j < m;j++)
	{
		cin>>w[i][j];
		
		if(w[i][j]  > x) 
		legal.push_back({i,j});
	}
	
	if(!legal.size())
	{
		cout<<-1<<endl;
		return 0;
	} 
	
	int d1[N][N],d2[N][N];
	memset(d1,-1,sizeof d1);
	memset(d2,-1,sizeof d2);
	bfs(sx,sy,d1);
	bfs(ex,ey,d2);
	
	bool flag=false;
	int ans=1e9;
	for(auto r:legal)
	{
		if(d1[r.x][r.y] > 0 && d2[r.x][r.y] > 0)
		{
			flag=true;
			ans=min(ans,d1[r.x][r.y]+d2[r.x][r.y]);
		}
	}
	
	if(flag) cout<<ans<<endl;
	else cout<<-1<<endl;
	
	return 0;
}


 

E.寻找小竹!

第一种方法:(图的存储,线性筛法,最大公约数,dfs)

#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=1e6+10,M=5e6+10;
vector<int> edges[N];
int c[N];
int dp[N];
bool st[M];
int minp[M];
int primes[M];
int cnt;
int n;

bool ok(int a,int b)
{
    int d=__gcd(a,b);
    vector<int> v;
    
    while(d > 1)
    {
        int mi=minp[d];
        v.push_back(mi);
        
        while(d%mi == 0) d/=mi;
    }
    
    return v.size() >= 2;
}

void dfs(int u,int fa)
{
    dp[u]=1;
    
    for(auto t:edges[u])
    {
        if(t == fa) continue;
        dfs(t,u);
        if(ok(c[u],c[t])) dp[u]+=dp[t];
    }
}

void screen_primes()
{
    for(int i=2;i <= M;i++)
    {
        if(!st[i])
        {
            primes[cnt++]=i;
            minp[i]=i;
            st[i]=true;
        }
        
        for(int j=0;primes[j] <= M/i;j++)
        {
            st[primes[j]*i]=true;
            minp[primes[j]*i]=primes[j];
            if(i%primes[j] == 0) break;
        }
    }
}

int main()
{
    screen_primes();
    
    cin>>n;
    
    for(int i=1;i <= n;i++) scanf("%d",&c[i]);
    
    for(int i=0;i < n-1;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        
        edges[x].push_back(y);
        edges[y].push_back(x);
    }
    
    dfs(1,-1);
    
    int ans=1;
    for(int i=1;i <= n;i++)
    ans=max(ans,dp[i]);
    
    cout<<ans<<endl;
    
    return 0;
}

第二种方法(并查集(外加子集大小的维护),埃氏筛法,最大公约数)

#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=1e6+10,M=5e6+10;
vector<int> edges[N];
int c[N];
int dp[N];
bool st[M];
int minp[M];
int primes[M];
int cnt;
int n;

bool ok(int a,int b)
{
    int d=__gcd(a,b);
    vector<int> v;
    
    while(d > 1)
    {
        int mi=minp[d];
        v.push_back(mi);
        
        while(d%mi == 0) d/=mi;
    }
    
    return v.size() >= 2;
}

void dfs(int u,int fa)
{
    dp[u]=1;
    
    for(auto t:edges[u])
    {
        if(t == fa) continue;
        dfs(t,u);
        if(ok(c[u],c[t])) dp[u]+=dp[t];
    }
}

void screen_primes()
{
    for(int i=2;i <= M;i++)
    {
        if(!st[i])
        {
            primes[cnt++]=i;
            minp[i]=i;
            st[i]=true;
        }
        
        for(int j=0;primes[j] <= M/i;j++)
        {
            st[primes[j]*i]=true;
            minp[primes[j]*i]=primes[j];
            if(i%primes[j] == 0) break;
        }
    }
}

int main()
{
    screen_primes();
    
    cin>>n;
    
    for(int i=1;i <= n;i++) scanf("%d",&c[i]);
    
    for(int i=0;i < n-1;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        
        edges[x].push_back(y);
        edges[y].push_back(x);
    }
    
    dfs(1,-1);
    
    int ans=1;
    for(int i=1;i <= n;i++)
    ans=max(ans,dp[i]);
    
    cout<<ans<<endl;
    
    return 0;
}