2017/10/20模拟赛

面包人(van
【题目描述】
W 为了对抗小 C 的骑士阵, 叫来了一车面包人来攻打他。由
于小 W 的后台很硬,他叫来的这一车总共有 n 个面包人,从 1~n
号。但小 C 很快就摸清了这车面包人的实力,他发现他们的实力跟
他们的编号以及编号的因数个数有着千丝万缕的关系。 假设τ (x)x
的因数个数,如果对于编号为 x 的面包人,满足任意编号比他小的面
包人 y, 都有τ (y)<τ (x),那么编号为 x 的面包人的实力就强于所有
编号比他小的面包人,否则他的实力就弱于所有编号比他小的面包
人。现在小 C 希望知道最强的和最弱的面包人的编号。
【输入数据】
输入只有一行, 一个正整数 n,表示面包人的个数。
【输出数据】
输出只有一行, 两个正整数,分别表示最强的和最弱的面包人编
号,两个数之间用空格隔开。
【样例输入】
10
【样例输出】
6 10
【数据范围】
对于 8%的数据, n<=10
对于 32%的数据, n<=10^5
另外 8%的数据, n 为质数;
对于 100%的数据, 1<=n<=2*10^9
【样例解释】
1~10 的因数个数分别是 1,2,2,3,2,4,2,4,3,4
所以实力排序从弱到强为: 10<9<8<7<5<3<1<2<4<6

PS:若 x=A^a+B^b+…+N^n.(A、B…均为质数)

    那么x的因数个数为 (a+1)*(b+1)*…*(n+1)

题解:首先,我们发现,因数最多的数一定是若干质数的积,且数据范围内所用到的质数很少,那么,我们暴力dfs枚举所用的因数即可。

代码如下:

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 int n,pr[10]={2,3,5,7,11,13,17,19,23,29},maxs,ans;
 5 void dfs(long long x,int cnt,int num){
 6     if(maxs<cnt) maxs=cnt,ans=x;
 7     if(maxs==cnt&&x<ans) ans=x;
 8     if(maxs>cnt&&x>ans) return;
 9     int sum=0;
10     while(x*pr[num]<=n){
11         x*=pr[num];
12         sum++;
13         dfs(x,cnt*(sum+1),num+1);
14     }
15 }
16 int main()
17 {
18     freopen("van.in","r",stdin);
19     freopen("van.out","w",stdout);
20     scanf("%d",&n);
21     if(n==1){printf("1 1");return 0;}
22     dfs(1,1,0);
23     printf("%d %d",ans,ans==n?n-1:n);
24     return 0;
25 }

 

 

寻呼机(pager
【题目描述】
H 和小 S 现在都居住在 B 城, B 城地图可以看做是一个 n*n
的网格图,小 H 住在(1,1),小 S 住在(n,n)B 城的通讯设施十分发达,
每一个格子中都建有一座类型为 cij 的通讯塔。 位于(i,j)的通讯塔对于
消息进行处理后只能将消息传输给位于(i+1,j)(i,j+1)的通讯塔。 一
天,小 H 通过传呼机给小 S 发了一道长度为 n-1 的消息。 所以消息依
次会经历 n-1 道加密、 1 道中枢处理和 n-1 道解密, 每个格子负责 1
道处理,所以一共会经过 2n-1 个格子;根据加密解密原则,每一次
解密会解开最后一次未被解密的加密,且该解密类型必须和对应的那
一次加密类型相同,具体表现为对应的两个格子类型 cij 相同。满足
以上条件能把信息成功从(1,1)传输到(n,n)的路径,称为合法信息通
路。等待回复的时间很漫长,小 H 端详着 B 城地图,他希望知道不
同的合法信息通路有多少种。
【输入数据】
第一行一个正整数 n, 表示 B 城大小。
接下来 n 行,每行 n 个整数,表示 B 城每个格子的类型 cij
【输出数据】
输出一个整数,表示合法信息通路的种数, 答案对 10^9+7 取模。
【样例输入】
3
1 2 3
1 1 2
2 1 1
【样例输出】
4
【数据范围】
对于 10%的数据, n<=10
对于 30%的数据, n<=50
对于 50%的数据, n<=100
另外 5%的数据,所有的 cij均相等;
另外 10%的数据, 0<=cij<=1
对于 100%的数据, 1<=n<=5000<=cij<=10^9
【样例解释】
4 条路径:
① (1,1)-(1,2)-(1,3)-(2,3)-(3,3): 12321;
② (1,1)-(1,2)-(2,2)-(2,3)-(3,3): 12121;
③ (1,1)-(2,1)-(2,2)-(3,2)-(3,3): 11111;
④ (1,1)-(2,1)-(3,1)-(3,2)-(3,3): 11211。

题解:因为xy特征值相加相同的数必在同一斜行,n^3 dp即可,内存不够所以用滚动数组。

变量声明:f[i][j][k](i从0开始)表示第i斜行第j行的数到第n-2-i斜行第k行的数的方案数。

状态转移方程:f[i][j][k]=f[i-1][j][k]+f[i-1][j-1][k]+f[i-1][j][k+1]+f[i-1][j-1][k+1]

代码如下:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #define ljm 1000000007
 5 using namespace std;
 6 int n,s[505][505],I=1;
 7 long long f[2][505][505],ans;
 8 int main()
 9 {
10     freopen("pager.in","r",stdin);
11     freopen("pager.out","w",stdout);
12     scanf("%d",&n);
13     for(int i=1;i<=n;i++)
14         for(int j=1;j<=n;j++) scanf("%d",&s[i][j]);
15     if(s[1][1]!=s[n][n]){printf("0");return 0;}
16     f[0][1][n]=1;
17     for(int i=1;i<=n-1;i++){
18         memset(f[I],0,sizeof(f[I]));
19         for(int j=1;j<=i+1;j++)
20             for(int k=n-i;k<=n;k++){
21                 int p1=i+2-j,p2=2*n-i-k;
22                 if(s[j][p1]==s[k][p2])
23                     f[I][j][k]=(f[I^1][j-1][k]+f[I^1][j][k+1]+f[I^1][j-1][k+1]+f[I^1][j][k])%ljm;
24             }
25         I^=1;
26     }I^=1;
27     for(int i=1;i<=n;i++) ans=(ans+f[I][i][i])%ljm;
28     printf("%lld",ans%ljm);
29     return 0;
30 }

 

疏散(nuclear)
【题目描述】
没有什么是一颗核弹解决不了的,如果有,那就来两颗。
你的营地现在正在接受小 C 的核弹轰炸,心灵控制仪矿场啥的估
计都要没了。你现在需要紧急疏散你各个建筑物里的部队,你的营地
里共有 n 个建筑,疏散第 i 个建筑里的部队需要 ti 的时间, 在同一时
刻内,你只能疏散一个建筑内的部队。然而你已经通过侦查部队知道
了小 C 对于你的营地的轰炸方案,你的第 i个建筑会在 si时刻被炸毁,
如果一个建筑里的部队正在疏散或还未疏散时建筑被炸毁,那么这个
建筑里的部队就不能算被成功疏散,为了能够再积蓄兵力与小 C 一
战,你希望疏散尽量多的建筑里的部队。
【输入数据】
第一行一个正整数 n,表示建筑个数。
接下来 n 行,每行两个整数, ti 和 si。含义如题中所述。
【输出数据】
输出只有一行,表示最多能疏散多少建筑里的部队。
【样例输入】
3
1 1
10 101
100 101

【样例输出】
2
【数据范围】
对于 10%的数据, n<=10;
对于 20%的数据, n,ti,si<=2000;
对于 50%的数据, n,ti,si<=20000
另外 10%的数据,满足所有 si都相等。
另外 20%的数据,满足所有 ti都相等。
对于 100%的数据, 1<=n<=300000, 0<=si,ti<=10^9。
【样例解释】
先疏散第 1个建筑, 再疏散第 2或第 3 个建筑。

据, n<=10;对于 20%的数据, n,ti,si<=2000;对于 50%的数据, n,ti,si<=20000另外 10%的数据,满足所有 si都相等。另外 20%的数据,满足所有 ti都相等。对于 100%的数据, 1<=n<=300000, 0<=si,ti<=10^9。【样例解释】先疏散第 1个建筑, 再疏散第 2或第 3 个建筑。

 题解:首先考虑贪心,我们把建筑按摧毁时间从小到大排序,若能疏散就疏散,若无法疏散就与已疏散的建筑所花时间最多的作比较,若小则替换,我们可以用堆维护这个最大值。

代码如下:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<queue>
 5 #define MN 300005
 6 using namespace std;
 7 int n,ans; long long sum;
 8 struct node{int t,s;}a[MN];
 9 priority_queue<int> pq;
10 bool cmp(node x,node y){return x.s<y.s;}
11 int main()
12 {
13     freopen("nuclear.in","r",stdin);
14     freopen("nuclear.out","w",stdout);
15     scanf("%d",&n);
16     for(int i=1;i<=n;i++) scanf("%d%d",&a[i].t,&a[i].s);
17     sort(a+1,a+1+n,cmp);
18     for(int i=1;i<=n;i++){
19         if(sum+a[i].t<=a[i].s) ans++,sum+=a[i].t,pq.push(a[i].t);
20         else if(!pq.empty()&&a[i].t<pq.top()){
21             sum+=a[i].t-pq.top();
22             pq.pop(); pq.push(a[i].t);
23         }
24     }
25     printf("%d",ans);
26     return 0;
27 }

 

posted @ 2017-10-24 14:02  Beginner_llg  阅读(299)  评论(0编辑  收藏  举报