一丶双核处理
一种双核CPU的两个核能够同时的处理任务,现在有n个已知数据量的任务需要交给CPU处理,假设已知CPU的每个核1秒可以处理1kb,每个核同时只能处理一项任务。n个任务可以按照任意顺序放入CPU进行处理,现在需要设计一个方案让CPU处理完这批任务所需的时间最少,求这个最小的时间。
思路:如果两个CPU处理任务所用时间的差越大 则ans越大 所以我们使一个cpu的处理时间尽量接近sum/2
跑一个容量为sum/2的01背包即可
输入都是1024的倍数 都除以1024 来节省空间
1 #include <cstdio>代码
2 #include <cctype>
3 #include <algorithm>
4 #define max(a,b) a>b?a:b
5
6 const int MAXN=110;
7 const int MAXM=2100000;
8
9 int n,sum;
10
11 int a[MAXN],v[MAXN],dp[MAXM];
12
13 inline void read(int&x) {
14 int f=1;register char c=getchar();
15 for(x=0;!isdigit(c);c=='-'&&(f=-1),c=getchar());
16 for(;isdigit(c);x=x*10+c-48,c=getchar());
17 x=x*f;
18 }
19
20 int hh() {
21 read(n);
22 for(int i=1;i<=n;++i) read(a[i]),v[i]=a[i]/1024,sum+=v[i];
23
24 for(int i=1;i<=n;++i)
25 for(int j=sum/2;j>=v[i];--j)
26 dp[j]=max(dp[j],dp[j-v[i]]+v[i]);
27 printf("%d\n",(sum-dp[sum/2])*1024);
28
29 return 0;
30 }
31
32 int sb=hh();
33 int main(int argc,char**argv) {;}
二丶赶去公司
终于到周末啦!小易走在市区的街道上准备找朋友聚会,突然服务器发来警报,小易需要立即回公司修复这个紧急bug。假设市区是一个无限大的区域,每条街道假设坐标是(X,Y),小易当前在(0,0)街道,办公室在(gx,gy)街道上。小易周围有多个出租车打车点,小易赶去办公室有两种选择,一种就是走路去公司,另外一种就是走到一个出租车打车点,然后从打车点的位置坐出租车去公司。每次移动到相邻的街道(横向或者纵向)走路将会花费walkTime时间,打车将花费taxiTime时间。小易需要尽快赶到公司去,现在小易想知道他最快需要花费多少时间去公司。
思路:一道初中数学题,先找一个最近的出租车打车点 然后再去公司
注意这个是有可能比车跑的快的....
1 #include <cstdio>代码
2 #include <cctype>
3 #include <algorithm>
4 #define min(a,b) a<b?a:b
5
6 const int INF=0x7fffffff;
7 const int MAXN=110;
8
9 int n,gx,gy,wt,tt,px,py;
10
11 int x[MAXN],y[MAXN];
12
13 inline void read(int&x) {
14 int f=1;register char c=getchar();
15 for(x=0;!isdigit(c);c=='-'&&(f=-1),c=getchar());
16 for(;isdigit(c);x=x*10+c-48,c=getchar());
17 x=x*f;
18 }
19
20 void pd(int xx,int yy,int&ans) {
21 int dis=abs(xx)+abs(yy);
22 int dist=abs(xx-gx)+abs(yy-gy);
23 if(dis*wt+dist*tt<ans) ans=dis*wt+dist*tt;
24 }
25
26 int hh() {
27 read(n);
28 for(int i=1;i<=n;++i) read(x[i]);
29 for(int i=1;i<=n;++i) read(y[i]);
30 read(gx);read(gy);read(wt);read(tt);
31
32 int ans1=INF;
33 for(int i=1;i<=n;++i)
34 pd(x[i],y[i],ans1);
35 int ans2=(abs(gx)+abs(gy))*wt;
36 printf("%d\n",min(ans1,ans2));
37
38 return 0;
39 }
40
41 int sb=hh();
42 int main(int argc,char**argv) {;}
三丶调整队形
在幼儿园有n个小朋友排列为一个队伍,从左到右一个挨着一个编号为(0~n-1)。其中有一些是男生,有一些是女生,男生用'B'表示,女生用'G'表示。小朋友们都很顽皮,当一个男生挨着的是女生的时候就会发生矛盾。作为幼儿园的老师,你需要让男生挨着女生或者女生挨着男生的情况最少。你只能在原队形上进行调整,每次调整只能让相邻的两个小朋友交换位置,现在需要尽快完成队伍调整,你需要计算出最少需要调整多少次可以让上述情况最少。例如:
GGBBG -> GGBGB -> GGGBB
这样就使之前的两处男女相邻变为一处相邻,需要调整队形2次
思路:两次冒泡排序,第一次让女生在前 记录交换次数
第二次男生在前 记录交换次数 取小
1 #include <cstdio>代码
2 #include <cctype>
3 #include <cstring>
4 #include <iostream>
5
6 const int MAXN=110;
7
8 int n;
9
10 int a[MAXN];
11
12 char s[MAXN];
13
14 int hh() {
15 scanf("%s",s+1);
16 n=strlen(s+1);
17 for(int i = 1;i <= n;++ i)
18 if(s[i] == 'B') a[i] = 1;
19 else a[i] = 0;
20 int t=0;
21 for(int i = 1;i <= n;++ i)
22 for(int j = 2;j <= n;++ j) {
23 if(a[j] < a[j-1]) {
24 std::swap(a[j],a[j-1]);
25 ++t;
26 }
27 }
28 for(int i=1;i<=n;++i) if(s[i] == 'B') a[i]=1; else a[i]=0;
29 int ans = 0;
30 for(int i = 1;i <= n;++ i)
31 for(int j = 2;j <= n;++ j) {
32 if(a[j] > a[j-1]) {
33 std::swap(a[j],a[j-1]);
34 ++ans;
35 }
36 }
37 ans=std::min(ans,t);
38 printf("%d\n",ans);
39 return 0;
40 }
41
42 int sb=hh();
43 int main(int argc,char**argv) {;}
四丶消除重复元素
小易有一个长度为n序列,小易想移除掉里面的重复元素,但是小易想是对于每种元素保留最后出现的那个。小易遇到了困难,希望你来帮助他。
思路:元素不是很大 统计每次元素出现次数
从1到n扫一遍 a[i]出现的次数减一 当这是最后一次出现时 输出
1 #include <cstdio>代码
2 #include <cctype>
3
4 const int MAXN=110;
5
6 int n,tot;
7
8 int a[MAXN],t[MAXN*10],ans[MAXN];
9
10 inline void read(int&x) {
11 int f=1;register char c=getchar();
12 for(x=0;!isdigit(c);c=='-'&&(f=-1),c=getchar());
13 for(;isdigit(c);x=x*10+c-48,c=getchar());
14 x=x*f;
15 }
16
17 int hh() {
18 read(n);
19 for(int i=1;i<=n;++i) read(a[i]),++t[a[i]];
20
21 for(int i=1;i<=n;++i) {
22 if(t[a[i]]>1) --t[a[i]];
23 else if(t[a[i]]==1) ans[++tot]=a[i];
24 }
25 for(int i=1;i<tot;++i) printf("%d ",ans[i]);
26 printf("%d\n",ans[tot]);
27
28 return 0;
29 }
30
31 int sb=hh();
32 int main(int argc,char**argv) {;}
五丶魔力手环
小易拥有一个拥有魔力的手环上面有n个数字(构成一个环),当这个魔力手环每次使用魔力的时候就会发生一种奇特的变化:每个数字会变成自己跟后面一个数字的和(最后一个数字的后面一个数字是第一个),一旦某个位置的数字大于等于100就马上对100取模(比如某个位置变为103,就会自动变为3).现在给出这个魔力手环的构成,请你计算出使用k次魔力之后魔力手环的状态。
思路:k太大,所以先找一下规律 最后惊讶的发现,并没有什么规律 ........
其实矩阵乘法 可做
当n=3时 矩阵如下图
快速幂加速一下就好了
1 #include <cstdio>代码
2 #include <cctype>
3
4 const int MAXN=110;
5
6 int n,k,tot;
7
8 int a[MAXN];
9
10 struct node {
11 int a[MAXN][MAXN];
12 friend inline node operator * (node x,node y) {
13 node z;
14 for(int i = 1;i <= n;++ i)
15 for(int j = 1;j <= n;++ j)
16 z.a[i][j]=0;
17
18 for(int i = 1;i <= n;++ i)
19 for(int j = 1;j <= n;++ j)
20 for(int k = 1;k <= n;++ k)
21 z.a[i][j]=(z.a[i][j] + x.a[i][k] * y.a[k][j])%100;
22 return z;
23 }
24 };
25 node p;
26
27 inline void read(int&x) {
28 int f=1;register char c=getchar();
29 for(x=0;!isdigit(c);c=='-'&&(f=-1),c=getchar());
30 for(;isdigit(c);x=x*10+c-48,c=getchar());
31 x=x*f;
32 }
33
34 node quick_pow(node t,int k) {
35 node ans;
36 for(int i=1;i<=n;++i)
37 for(int j=1;j<=n;++j)
38 if(i==j) ans.a[i][j]=1;
39 else ans.a[i][j]=0;
40
41 while(k) {
42 if(k&1) ans=ans*t;
43 k>>=1;
44 t=t*t;
45 }
46 return ans;
47 }
48
49 int hh() {
50 read(n);read(k);
51 for(int i=1;i<=n;++i) read(a[i]);
52 for(int i=1;i<=n;++i) p.a[i][i]=1,p.a[i+1][i]=1;
53 p.a[1][n]=1;
54
55 node tmp=quick_pow(p,k);
56 int ans;
57 for(int i=1;i<=n;++i) {
58 ans=0;
59 for(int j=1;j<=n;++j)
60 ans=(ans+a[j]*tmp.a[j][i])%100;
61 if(i==n) break;
62 printf("%d ",ans);
63 }
64 printf("%d",ans);
65
66 return 0;
67 }
68
69 int sb=hh();
70 int main(int argc,char**argv) {;}
六丶工作安排
现在有n位工程师和6项工作(编号为0至5),现在给出每个人能够胜任的工作序号表(用一个字符串表示,比如:045,表示某位工程师能够胜任0号,4号,5号工作)。现在需要进行工作安排,每位工程师只能被安排到自己能够胜任的工作当中去,两位工程师不能安排到同一项工作当中去。如果两种工作安排中有一个人被安排在的工作序号不一样就被视为不同的工作安排,现在需要计算出有多少种不同工作安排计划。
思路:DFS 第i项工作交给谁来做
1 #include <cstdio>代码
2 #include <cctype>
3 #include <cstring>
4
5 const int MAXN=10;
6
7 int n,len,ans;
8
9 int a[MAXN][MAXN];
10
11 char s[MAXN];
12
13 bool vis[MAXN];
14
15 void DFS(int num) {
16 if(num==n+1) {
17 ++ans;
18 return;
19 }
20 for(int i=0;i<6;++i) {
21 if(!vis[i]&&a[num][i]) {
22 vis[i]=true;
23 DFS(num+1);
24 vis[i]=false;
25 }
26 }
27 }
28
29 int hh() {
30 scanf("%d",&n);
31
32 for(int i=1;i<=n;++i) {
33 scanf("%s",s+1);
34 len=strlen(s+1);
35 for(int j=1;j<=len;++j) {
36 int t=s[j]-'0';
37 a[i][t]=1;
38 }
39 }
40
41 DFS(1);
42 printf("%d\n",ans);
43
44 return 0;
45 }
46
47 int sb=hh();
48 int main(int argc,char**argv) {;}
七丶集合
小易最近在数学课上学习到了集合的概念,集合有三个特征:1.确定性 2.互异性 3.无序性.
小易的老师给了小易这样一个集合:
S = { p/q | w ≤ p ≤ x, y ≤ q ≤ z }
需要根据给定的w,x,y,z,求出集合中一共有多少个元素。小易才学习了集合还解决不了这个复杂的问题,需要你来帮助他。
思路:元素不一定是整数 用set即可
1 #include <set>代码
2 #include <cstdio>
3 #include <cctype>
4
5 const int MAXN=10010;
6
7 int w,x,y,z,ans;
8
9 std::set<double> s;
10
11 int hh() {
12 scanf("%d%d%d%d",&w,&x,&y,&z);
13
14 for(int i=w;i<=x;++i)
15 for(int j=y;j<=z;++j) {
16 double t=(double)i/j;
17 s.insert(t);
18 }
19 printf("%d\n",s.size());
20
21 return 0;
22 }
23
24 int sb=hh();
25 int main(int argc,char**argv) {;}
八丶奇怪的表达式求值
常规的表达式求值,我们都会根据计算的优先级来计算。比如*/的优先级就高于+-。但是小易所生活的世界的表达式规则很简单,从左往右依次计算即可,而且小易所在的世界没有除法,意味着表达式中没有/,只有(+, - 和 *)。现在给出一个表达式,需要你帮忙计算出小易所在的世界这个表达式的值为多少。
思路:O(n)模拟
1 #include <cstdio>代码
2 #include <cctype>
3 #include <cstring>
4
5 const int MAXN=100010;
6
7 int len,top,cnt;
8
9 char s[MAXN];
10
11 int hh() {
12 scanf("%s",s+1);
13 len=strlen(s+1);
14 int ans=s[1]-'0';
15 for(int i=2;i<=len;++i) {
16 if(s[i]=='*') {
17 ans*=(int)s[i+1]-'0';
18 ++i;
19 }
20 else {
21 if(s[i]=='+') ans+=(int)s[i+1]-'0';
22 else ans-=(int)s[i+1]-'0';
23 ++i;
24 }
25 }
26 printf("%d\n",ans);
27 return 0;
28 }
29
30 int sb=hh();
31 int main(int argc,char**argv) {;}
九丶涂棋盘
小易有一块n*n的棋盘,棋盘的每一个格子都为黑色或者白色,小易现在要用他喜欢的红色去涂画棋盘。小易会找出棋盘中某一列中拥有相同颜色的最大的区域去涂画,帮助小易算算他会涂画多少个棋格。
思路:找每一列中最长的连续相同子串
1 #include <cstdio>代码
2 #include <cctype>
3
4 const int MAXN=100;
5
6 int n;
7
8 int m[MAXN][MAXN];
9
10 char s[MAXN];
11
12 int hh() {
13 scanf("%d",&n);
14 for(int i=1;i<=n;++i) {
15 scanf("%s",s+1);
16 for(int j=1;j<=n;++j)
17 if(s[j]=='B') m[i][j]=1;
18 }
19
20 int ans=0;
21 for(int i=1;i<=n;++i) {
22 int len=1;
23 for(int j=2;j<=n;++j) {
24 if(m[j][i]==m[j-1][i]) {
25 ++len;
26 ans=ans<len?len:ans;
27 }
28 else len=1;
29 }
30 }
31 printf("%d\n",ans);
32 return 0;
33 }
34
35 int sb=hh();
36 int main(int argc,char**argv) {;}
十丶小易记单词
小易参与了一个记单词的小游戏。游戏开始系统提供了m个不同的单词,小易记忆一段时间之后需要在纸上写出他记住的单词。小易一共写出了n个他能记住的单词,如果小易写出的单词是在系统提供的,将获得这个单词长度的平方的分数。注意小易写出的单词可能重复,但是对于每个正确的单词只能计分一次。
思路:感觉map可过 所以我就写了trie树
1 #include <cstdio>代码
2 #include <cctype>
3 #include <cstring>
4
5 const int MAXN=100010;
6
7 int n,m,tot,ans;
8
9 struct node {
10 int next[27];
11 };
12 node t[MAXN];
13
14 char s[MAXN];
15
16 bool vis[MAXN],isvis[MAXN];
17
18 void build_tree() {
19 int now=0;
20 int len=strlen(s+1);
21 for(int i=1;i<=len;++i) {
22 int x=s[i]-'a'+1;
23 if(!t[now].next[x]) t[now].next[x]=++tot;
24 now=t[now].next[x];
25 }
26 isvis[now]=true;
27 }
28
29 void find() {
30 int now=0;
31 int len=strlen(s+1);
32 for(int i=1;i<=len;++i) {
33 int x=s[i]-'a'+1;
34 now=t[now].next[x];
35 }
36 if(!vis[now]&&isvis[now]) ans+=len*len,vis[now]=true;
37 return;
38 }
39
40 int hh() {
41 scanf("%d%d",&n,&m);
42 for(int i=1;i<=n;++i) {
43 scanf("%s",s+1);
44 build_tree();
45 }
46 for(int i=1;i<=m;++i) {
47 scanf("%s",s+1);
48 find();
49 }
50 printf("%d\n",ans);
51 return 0;
52 }
53
54 int sb=hh();
55 int main(int argc,char**argv) {;}
十一丶堆砖块
小易有n块砖块,每一块砖块有一个高度。小易希望利用这些砖块堆砌两座相同高度的塔。为了让问题简单,砖块堆砌就是简单的高度相加,某一块砖只能使用在一座塔中一次。小易现在让能够堆砌出来的两座塔的高度尽量高,小易能否完成呢。
思路:动态规划
dp[i][j] 表示用了前i块砖 高度差为j 高度较小的那堆为dp[i][j]
第i块砖不用 dp[i][j]=dp[i-1][j]
第i块砖放在高度小的那堆上 这堆高度还是小于另外一堆 dp[i][j]=max(dp[i-1][j+a[i]]+a[i]);
第i块砖放在高度小的那堆上 这堆高度超过另外一堆 dp[i][]j=max(dp[i-1][a[i]-j]+a[i]-j)
第i块砖放在高度大的那堆上 dp[i][j]=max(dp[i][j-a[i]]+j-a[i])
1 #include <cstdio>代码
2 #include <cctype>
3 #include <cstring>
4 #define max(a,b) a<b?b:a
5
6 const int MAXM=500010;
7 const int MAXN=60;
8
9 int n,sum,Length;
10
11 int a[MAXN],dp[2][MAXM];
12
13 inline void read(int&x) {
14 int f=1;register char c=getchar();
15 for(x=0;!isdigit(c);c=='-'&&(f=-1),c=getchar());
16 for(;isdigit(c);x=x*10+c-48,c=getchar());
17 x=x*f;
18 }
19
20 int hh() {
21 read(n);
22 for(int i=1; i<=n; ++i) read(a[i]),sum+=a[i];
23
24 memset(dp[0],-1,sizeof dp[0]);
25 dp[0][0]=0;
26
27 for(int i=1; i<=n; ++i)
28 for(int j=0; j<=sum; ++j) {
29 dp[i&1][j]=dp[(i-1)&1][j];
30 if(j+a[i]<=sum && dp[(i-1)&1][j+a[i]] >=0)
31 dp[i&1][j]=max(dp[i&1][j],dp[(i-1)&1][j+a[i]]+a[i]);
32 if(a[i]-j>=0 && dp[(i-1)&1][a[i]-j] >=0)
33 dp[i&1][j]=max(dp[i&1][j],dp[(i-1)&1][a[i]-j]+a[i]-j);
34 if(j-a[i]>=0 && dp[(i-1)&1][j-a[i]] >=0)
35 dp[i&1][j]=max(dp[i&1][j],dp[(i-1)&1][j-a[i]]);
36 }
37
38 if(dp[n&1][0]==0) printf("-1\n");
39 else printf("%d\n",dp[n&1][0]);
40
41 return 0;
42 }
43
44 int sb=hh();
45 int main(int argc,char**argv) {;}
十二丶分饼干
易老师购买了一盒饼干,盒子中一共有k块饼干,但是数字k有些数位变得模糊了,看不清楚数字具体是多少了。易老师需要你帮忙把这k块饼干平分给n个小朋友,易老师保证这盒饼干能平分给n个小朋友。现在你需要计算出k有多少种可能的数值。
思路: 这道题很有意思 搜索只能过60%
还是动态规划
dp[i][j]表示 用了前i位 n%余j的方案数
1 #include <cstdio>代码
2 #include <cctype>
3 #include <cstring>
4
5 typedef long long LL;
6
7 const int MAXN=20;
8
9 int n;
10
11 LL dp[MAXN][10000];
12
13 char s[MAXN];
14
15 int hh() {
16 scanf("%s",s+1);scanf("%d",&n);
17
18 dp[0][0]=1;
19 int len=strlen(s+1);
20 for(int i=1;i<=len;++i) {
21 int nj;
22 for(int j=0;j<=n-1;++j) {
23 if(s[i]=='X')
24 for(int x=0;x<=9;++x) {
25 nj=(j*10+x)%n;
26 dp[i][nj]+=dp[i-1][j];
27 }
28 else {
29 nj=(j*10+s[i]-'0')%n;
30 dp[i][nj]+=dp[i-1][j];
31 }
32 }
33 }
34 printf("%lld",dp[len][0]);
35
36 return 0;
37 }
38
39 int sb=hh();
40 int main(int argc,char**argv) {;}