【金华集训 && 题解】 考试题题解

//这里只写我已经A的。。


一、 1 0 9 + 7 10^9+7 109+7

You are given three non-negative integers, x, y, z. Your task is to find the smallest non-negative integer n with all of the following conditions:

  • n mod 17=x
  • n mod 107=y
  • n mod 1000000007(=109+7)=z
Solution
  • 第一眼:中国剩余定理。
  • 后来发现不用
  • 由于1000000007特别大
  • 所以符合范围的数肯定不会很多
  • 不断暴力枚举即可
  • 经过严格的证明 可以得出最多也就17*107次
  • 所以可以AC
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
int x,y,z;
int ans=0;
signed main(){
    scanf("%lld %lld %lld",&x,&y,&z);
    ans=z;
    for (;ans%17!=x || ans%107!=y;ans+=1000000007);
	printf("%lld",ans);
	return 0; 
}

二、Coins

There are 1-, 5-, 10-, 50-, 100-, 500- yen coins, and you have an infinite number of coins of each type.

For a given positive integer x, let f(x) be the smallest number of coins you have to use to pay exactly x yen. For example, f(2018)=9 because 2018=1+1+1+5+10+500+500+500+500.

You are given a positive integer N. Count the number of positive integers x such that f(x)=N.

Solution
  • 第一眼是完全背包
  • 一看范围发现不行
  • 仔细看了一眼题面,发现要是最小的??
  • 这意味着只能用4个1,1个5,4个10,1个50,4个100!!
  • 所以我们就可以根据这个暴力了
  • 500填几个都行
  • 时间复杂度非常可观
Code
#include<bits/stdc++.h>
using namespace std;
long long n;
int ans=0;

int main(){
    scanf("%lld",&n);
    n-=n/500;
    for (int yi=0;yi<5;yi++)
      for (int wu=0;wu<2;wu++)
        for (int shi=0;shi<5;shi++)
          for (int ws=0;ws<2;ws++)
            for (int yb=0;yb<5;yb++)
              if (yi+wu+shi+ws+yb <= n) ans++;
    printf("%d",ans);
    return 0;
}

三、Yet another vector problem

You’re given a 0-based array a of length n. Answer Q queries of form: what is sum of elements a[i], such as i modulo p = q, for given p and q.

Solution
  • 第一想法:dp,一看范围,不对啊??
  • 不管,先把dp敲了一遍,交了一发没过,想优化。
  • 不过。。这题似乎可以卡范围??
  • 仔细算了一下范围,发现当n>=100时,这是可以卡过的??
  • 于是就是暴力与正解的结合,交了一发,A了
Code
#include <bits/stdc++.h>
using namespace std;
#define gc getchar()
int n,q;
int a[100010];
int f[100010][110];

int read(){
    char ch=gc;
    int ans=0;
    bool f=0;
    while (ch<'0' || ch>'9') f=ch=='-',ch=gc;
    while (ch>='0' && ch<='9') ans=(ans<<1)+(ans<<3)+ch-48,ch=gc;
    return f?-ans:ans;
}

void work(int x,int y){
    long long ans=0;
    for (signed int i=x;i<n;i+=y) ans+=a[i]*1ll;
    printf("%lld\n",ans);
    return;
}

int main(void)
{
    n=read(),q=read();
    for (int i=0;i<n;i++) a[i]=read();
    for (signed int i=n-1;i>=0;i--)
      for (signed int j=0;j<=105;j++)
        if (i+j>n-1) f[i][j]=a[i];
        else f[i][j] = f[i+j][j]+a[i];
    for (signed int i=1;i<=q;i++){
        int P,Q;
        P=read(),Q=read();
        if (Q == 0) {printf("0\n");continue;}
        if (Q<=95) printf("%d\n",f[P][Q]);
        else work(P,Q);
    }
    return 0;
}

四、Grouping

Suppose there are N people in ZJU, whose ages are unknown. We have some messages about them. The i-th message shows that the age of person si is not smaller than the age of person ti. Now we need to divide all these N people into several groups. One’s age shouldn’t be compared with each other in the same group, directly or indirectly. And everyone should be assigned to one and only one group. The task is to calculate the minimum number of groups that meet the requirement.

Solution
  • 对于同一个环中的人,肯定不能互相在一起
  • 考虑强连通分量缩点,点权为这个连同分量中点的个数
  • 同样,在同一条链中的人肯定也不能互相分到一组
  • 所以问题转化为缩点后求新图的最长链
  • 不过,这个代码是有锅的
Code
#include<bits/stdc++.h>
using namespace std;
int n,m;
struct node{
    int x,y,Next; 
}e[600100];
int X[100010],Y[100010];
int fam[100010];
int Dp[101100];
int in[1010000];
int sta[100010];
vector < int > a[200010];
vector <int> scc[200010];
int linkk[100010];
int dfn[100010];
int low[100100];
int num,top=0,len=0,cnt=0;
bool isi[100100];
int con[1000010];

void insert(int x,int y){
    e[++len] = (node){x,y,linkk[x]};
    linkk[x] = len;
}


void tarjan(int x){
    dfn[x] = low[x] = ++num;
    sta[++top] = x;
    isi[x] = 1;
    for (int i=linkk[x];i;i=e[i].Next){
	    int y=e[i].y;
	    if (!dfn[y]) tarjan(y) , low[x] = min(low[x] , low[y]);
	    else if (isi[y]) low[x] = min(low[x] , dfn[y]);
	}
	if (dfn[x] == low[x]) {
		cnt ++ ;
		int y;
		do {
			y = sta[top--];
			isi[y] = 0;
			fam[y] = cnt;
			con[cnt] ++;
			scc[cnt].push_back(y);
		}while( x != y );
	}
}

int dp(int x){
    if (Dp[x] > 0) return Dp[x];
    Dp[x] = 0;
//    cout<<"OK:"<<x<<endl;
    for (int i=0;i<a[x].size();i++){
	    int y=a[x][i];
	    Dp[x] = max(Dp[x] , dp(y));
	}
	Dp[x] += scc[x].size();
//	cout<<"x:"<<x<<' '<<Dp[x]<<' '<<con[x]<<endl; 
	return Dp[x];
}

void work(){
	int ans=0;
    len=0 , top=0 ,cnt=0 , num=0;
    memset(linkk,0,sizeof linkk);
    memset(fam,0,sizeof fam);
    memset(in,0,sizeof in);
    memset(sta,0,sizeof sta);
    memset(Dp,0,sizeof(Dp));
    memset(dfn,0,sizeof dfn);
    memset(low,0,sizeof low);
    memset(con,0,sizeof(con));
    memset(isi,0,sizeof(isi));
    for (int i=1;i<100009;i++) a[i].clear();
    for (int i=1;i<100009;i++) scc[i].clear();
    for (int i=1,x,y;i<=m;i++)
      scanf("%d %d",&X[i],&Y[i]),insert(X[i],Y[i]);
    for (int i=1;i<=n;i++)
      if (!dfn[i]) tarjan(i);
    len=0;
    memset(linkk,0,sizeof(linkk));
	for (int i=1;i<=m;i++)
	  if (fam[X[i]] != fam[Y[i]]) a[fam[X[i]]].push_back(fam[Y[i]]),in[fam[Y[i]]]++;
//	cout<<cnt<<endl;
//	for (int i=1;i<=n;i++) cout<<fam[i]<<' ';
//	cout<<endl;
//	for (int i=1;i<=cnt;i++) cout<<in[i]<<' ';
//	     cout<<"i:"<<i<<' ';
//	     for (int j=linkk[i];j;j=e[j].Next) cout<<e[j].y<<' ';
//	     cout<<endl<<"------------------------------"<<endl;
//	}
	for (int i=1;i<=cnt;i++)
	  if (!in[i]) ans = max(ans,dp(i));
	printf("%d\n",ans);
}

int main(){
    while (~scanf("%d %d",&n,&m)) work();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值