第一题

漏洞和补丁描述 Description
ICG模拟赛开始了!由FF博士带领的团队要开始准备ICG模拟赛了,但他们发现机房的电脑有很多漏洞。为了修补漏洞,只有下载各种补丁。 但是由于这些漏洞太过久远,不一定能找到能够修复漏洞的补丁。以下有n个漏洞和m个补丁,用字符串表示。若其中一个漏洞被一个补丁包含或包含一个补丁则认为这是一个可以被修复的漏洞。(不区分大小写,一个补丁可以修复多个漏洞,一个漏洞只能被修复一次) 输出能被修复的漏洞总数。
输入格式 Input Format  第一行,两个整数n,m; 第2行到第N+1行,表示漏洞的名称; 接下来M行表示能下载到的各个补丁的名称。
输出格式 Output Format 1个整数,表示能被修复的漏洞总数。

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 104
using namespace std;
char a[maxn][257];
char b[maxn][257];
bool v[maxn];
int p[257];
int n,m,ans=0;

int* get_next(char *temp)
{
	int i,j;
	int *next=new int[strlen(temp)];
	memset(next,0,sizeof(next));
	next[0]=-1;
	for(i=1;i<strlen(temp);i++)
	{
		j=next[i-1];
		while(j>=0&&temp[i]!=temp[j+1]) j=next[j];
		if(temp[i]==temp[j+1]) next[i]=j+1;
		else next[i]=-1;
	}
	return next;
}
int KMP(char* ori,char *temp,int *next)
{
	int i=0,j=0;
	while(i<strlen(ori)&&j<strlen(temp))
	{
		if(ori[i]==temp[j]) i++,j++;
		else if(j==0) i++;
		else j=next[j-1]+1;
	}
	if(j>=strlen(temp)) return i-j;
	else return -1;
}


int main()
{
    int i,j;
    cin>>n>>m;
    for (i=1;i<=n;i++)
    {
        cin>>a[i];
        for (j=0;j<strlen(a[i]);j++)
          if (a[i][j]>='A' && a[i][j]<='Z') a[i][j]+=32;
    }
    for (i=1;i<=m;i++)
    {
        cin>>b[i];
        for (j=0;j<strlen(b[i]);j++)
          if (b[i][j]>='A' && b[i][j]<='Z') b[i][j]+=32;
    }
    for (i=1;i<=n;i++)
    for (j=1;j<=m;j++)
    {
                   if (KMP(a[i],b[j],get_next(b[j]))>=0 || KMP(b[j],a[i],get_next(a[i]))>=0) 
                   {
                                      v[i]=true;
                   }
    }
    for (i=1;i<=n;i++) if (v[i]) ans++;
    cout<<ans<<endl;
    return 0;
}

第二题

MMT数描述 Description
  FF博士最近在研究MMT数(莫明堂数-_-)。如果对于一个数n,存在gcd(n,x)<>1并且n mod x<>0 那么x叫做n的MMT数显然这样的数可以有无限个。FF博士现在想知道在所有小于n的正整数里面有多少个n的MMT数
输入格式 Input Format
  仅一行一个数,为n
输出格式 Output Format
  所有小于n的正整数里面有多少个n的MMT数

#include<iostream>
#include<cmath>
using namespace std;
int n;
int ti,zhi;
int k[100000],tot=0;
int ans;
void calti(int n)
{
    ti=n;
    for (int i=2;i*i<=n;i++)
    {
        if ((n%i)==0) ti-=ti/i;
        while ((n%i)==0) n/=i;
    }
    if (n>1) ti-=ti/n;
}
void cal(int n)
{
     int i=2,t=(int)sqrt((double)n);
     while (i<=t)
     {
           if ((n % i)==0)
           {
                  tot++;
                  while (n % i==0) {n/=i;k[tot]++;}
           }
           i++;
     }
     if (n!=1) k[++tot]++;
     zhi=1;
     for (i=1;i<=tot;i++) zhi*=k[i]+1;
}
int main()
{
    cin>>n;
    calti(n);
    cal(n);
    ans=n+1-ti-zhi;
    cout<<ans<<endl;
    return 0;
}

第三题

软件下载描述 Description
  ICG大赛马上就要举行了,作为大赛的组委会兼参赛选手,信息组的成员们当然要做准备了,而其中十分重要的一项准备工作就是下载很多举办大赛必不可少的软件,已知现在机房有N台电脑,组委会列出了M个需要下载的软件及其大小Ai(即需要下载的时间),每个电脑同一时间只能下载一个软件,一个软件也只能由一个电脑下载,每个电脑下载速度相同且互不影响.因为有神器Cena的存在,每个软件只需由某一台电脑下载一次就能使整个机房的电脑普及该软件。现在ICG组委会想知道最快能在多长时间内下载完成。
输入格式 Input Format
  第1行:两个整数N、M,分别代表机房的电脑数及需要下载的软件数量。第2行:M个整数,第i个整数表示Ai的值。
输出格式 Output Format
 一行一个整数,表示能下载完所有软件的最短时间。

#include<iostream>
#include<cstdlib>
using namespace std;
int n,m,tot=0;
int l,r,mid;
int a[51];
bool v[51];
int t[51];
bool dfs(int d,int num,int rest)
{
     if (((n-d+1)*mid-t[d])<rest) return false;
     if (num==m) return true;
     for (int i=1;i<=m;i++)
     {
         if (!v[i])
         if (t[d]+a[i]<=mid)
         {
                           t[d]+=a[i];
                           v[i]=true;
                           if (dfs(d,num+1,rest-a[i])) return true;
                           v[i]=false;
                           t[d]-=a[i];
         }
         else
         if (d<n)
         {
             t[d+1]+=a[i];
             v[i]=true;
             if (dfs(d+1,num+1,rest-a[i])) return true;
             v[i]=false;
             t[d+1]-=a[i];
         }
         else return false;
     }
     return false;
}
int cmp(const void *a,const void *b)
{
    return *(int *)b-*(int *)a;
}

int main()
{
    int i;
    cin>>n>>m;
    for (i=1;i<=m;i++) {cin>>a[i];tot+=a[i];}
    qsort(a+1,m,sizeof(int),cmp);
    l=a[1];r=tot;
    while (l<r)
    {
          mid=(l+r)>>1;
          memset(v,false,sizeof(v));
          memset(t,0,sizeof(t));
          v[1]=true;
          t[1]=a[1];
          if (dfs(1,1,tot-a[1])) r=mid;
		  else l=mid+1;
    }
    cout<<r<<endl;
    return 0;
}

第四题

清理内奸描述 Description  

最近FF博士在玩一个游戏“三国杀杀杀”,他扮演一个英明的主公,四处清剿反贼。终于把反贼全部干掉了,可是他的手下还存在着一些内奸。经过他的观察和研究,终于发现了内奸的重要特征。内奸最重要的工作就是传递情报,所以内奸必须掌握各种加密方法。于是他们对素数有一种偏好,编号是素数的人全部是内奸。FF博士将指挥忠臣干掉内奸。忠臣和内奸排成一排,第i个人的编号为Bi。杀死内奸会获得一定量经验,等级为X的忠臣杀死任意等级的内奸会获得X点经验。每个人都有一定的攻击范围,若站在i位置的人攻击范围为k那么他可以杀[i-k,i+k]范围内的人,但是每个人都只有一次攻击的机会。内奸们并不知道自己的身份已经暴露,不会攻击任何人,只能做待宰的羔羊,FF博士确定了攻击方案后会在瞬间下令让忠臣行动,内奸会被秒(也就是内奸死亡不会对原来攻击范围造成影响)。
请帮FF博士计算
1、他这次最多能干掉多少内奸呢?2、在干掉内奸人数最多的情况下,他能获得最多多少经验?

输入格式 Input Format  

第一行一个数字n,代表FF博士手下有n个人第二行n个数,第i个数代表第i个人的编号Bi3~n+2行,每行2个数x  k 分别代表第i个人的等级和攻击范围。


输出格式 Output Format
  第一行是FF博士最多能干掉的内奸数量
第二行是FF博士在干掉最多内奸的基础上能获得的最多经验数。

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
int n;
struct node
{
       int x,k;
}e[1010];
struct lines
{
       int i,x;
}line[1010];
int bad,good;
int ans,tot=0,sum;
bool dog[1010],flag,v[1010];;
bool map[1010][1010];
int match[1010];
bool dfs(int x)
{
     for (int i=1;i<=n;i++)
     {
         if (dog[i]&&!v[i]&&map[x][i])
         {
             v[i]=true;
             if (match[i]==0||dfs(match[i])) 
             {
                               match[i]=x;
                               return true;
             }
         }
     }
     return false;
}
int cmp(const void *a,const void *b)
{
    return (*(lines *)b).x-(*(lines *)a).x;
}
int main()
{
//    freopen("tyvj.in","r",stdin);
//    freopen("tyvj.out","w",stdout);
    scanf("%d\n",&n);
    int x;
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        flag=1;
        if (x==1) continue;
        for (int j=2;j<=(int)sqrt((double)x);j++)
          if (x%j==0) {flag=0;break;}
        if (flag) 
        {
                  dog[i]=true;
                  bad++;
        }
    }
    good=n-bad;
    for (int i=1;i<=n;i++)
    {
        scanf("%d %d\n",&e[i].x,&e[i].k);
        for (int j=1;j<=e[i].k;j++)
        {
            if (i-j>0) map[i][i-j]=true;
            if (i+j<=n) map[i][i+j]=true;
        }
    }
    for (int i=1;i<=n;i++)
    {
        if (!dog[i]) {line[++tot].x=e[i].x;line[tot].i=i;}
    }
    qsort(line+1,tot,sizeof(lines),cmp);
    for (int i=1;i<=tot;i++)
    {
                memset(v,0,sizeof(v));
                if (dfs(line[i].i)) {ans++;sum+=line[i].x;}
    }
    printf("%d\n%d\n",ans,sum);
    return 0;
}