第五届合肥工业大学宣城校区程序设计大赛题解

问题 A: 小问题

时间限制: 1 Sec  内存限制: 128 MB  Special Judge

 

题目描述

林喵喵特别喜欢解决女孩子们提出的问题. 

于是, 有一天殷老师问了林喵喵一个小问题.
 
给出一个非空有限集合A, 其中包含元素若干, 给出一个元素p, 输出集合A的非空子集且元素p不属于那个子集.(即要求是A的非空子集并其中不存在元素p,输出所以符合要求的集合)
元素皆为整数,且 <=231-1

 

输入

第一行T表示测试组数
第二行有一个数N, 表示集合A内元素的数量 Card(A) N≤20
第三行有N个集合A的元素,以空格分隔
第四行有一个A的元素p

 

输出

 

为了降低难度, 你只需要输出每个集合内数字的数量与总和,  总和小于231-1
每个输出的集合占用一行
每行两个数字, 第一个数表示非空集合元素的数量, 第二个数表示非空集合元素的总和
集合之间的顺序可随意调整

 

 

样例输入

1 5 1 2 3 4 5 3

样例输出

1 1 1 2 2 3 1 4 2 5 2 6 3 7 1 5 2 6 2 7 3 8 2 9 3 10 3 11 4 12
 

水题之一。你可以用dfs搜索每一个位置的情况,或者用二进制模拟。聪明的做法是把要剔除的元素剔除掉,再输出所有可能情况。我当初没写剔除的做法就判断了,时间复杂度较高。
二进制模拟代码:
 
 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(0))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define LL long long
 5 #define mod 1000000007
 6 using namespace std;
 7 const int N=1e2+10;
 8 LL val[N];
 9 int T,n,m,h,p,ct,t;
10 LL sum;
11 int main()
12 {
13     scanf("%d",&T);
14     while(T--)
15     {
16         scanf("%d",&n);
17         for(int i=1;i<=n;i++)
18             scanf("%lld",&val[i]);
19         m=(1<<n)-1;
20         scanf("%d",&p);
21         for(int i=1;i<=n;i++)
22             if(p==val[i])
23             {
24                 p=i;
25                 break;
26             }
27         for(int i=1;i<=m;i++)
28         if(((i>>(p-1))&1)==0)
29         {
30             ct=0;
31             t=0;
32             sum=0;
33             h=i;
34             while(h)
35             {
36                 t++;
37                 if(h&1)
38                 {
39                     sum+=val[t];
40                     ct++;
41                 }
42                 h>>=1;
43             }
44             printf("%d %lld\n",ct,sum);
45         }
46     }
47     return 0;
48 }
49  
View Code

 

问题 B: 统计词频

时间限制: 1 Sec  内存限制: 128 MB
提交: 359  解决: 22

 

题目描述

给出一段英文文字, 统计每个单词出现的次数(忽略大小写)
单词字母范围为( a~z 或 A~Z ),没有奇怪的字符

 

输入

第一行组数T
第二行单词数N (N<=10000)
后面N行有N个非空的单词

 

输出

输出小写单词和数量,单词按照字典序排序输出
一个单词占一行

 

样例输入

1 4 hello world hello icpc

样例输出

hello 2 icpc 1 world 1
 

 
水题之二。写个map对每个string进行映射,然后用迭代器从头到尾输出就好了。
 
 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(0))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define LL long long
 5 #define mod 1000000007
 6 using namespace std;
 7 const int N=1e5+10;
 8 int T,n,m,h,p,ct,t;
 9 string s;
10 map<string,LL>::iterator it;
11 int main()
12 {
13     scanf("%d",&T);
14     while(T--)
15     {
16         scanf("%d",&n);
17         map<string,LL> num;
18         for(int i=1;i<=n;i++)
19         {
20             cin>>s;
21             for(int j=0;j<s.size();j++)
22                     s[j]=tolower(s[j]);
23             num[s]++;
24         }
25         for(it=num.begin();it!=num.end();it++)
26             printf("%s %lld\n",(it->first).c_str(),it->second);
27     }
28     return 0;
29 }
View Code

 

问题 C: 机房问题

时间限制: 2 Sec  内存限制: 128 MB
提交: 214  解决: 18

 

题目描述

在你们写题的时候,萌萌的林喵喵同学其实在暗中观察你们(Big Miao is watching you!)

其中观察的一项就是要统计出一段时间内哪个时刻上机人数最多。

你能否比林喵喵更快地统计出来呢?

 

输入

T表示组数
N表示数据数量
接下来N行每行三个整数t1,t2,n
表示n个学生在t1到t2使用了机房电脑(包含t1,t2)
0<t1<t2<=10000000
0<n<=10000000

 

输出

输出一个时间t, 这个时刻上机人数最多
若有多个最大值则输出最小的t

 

样例输入

1 3 1 2 1 1 3 1 2 5 2

样例输出

2

 


 
水题之三。数据范围给的这么大,一看就不能瞎暴力。
我们只需要遍历访问过的时间点就行了。这相当于一个离散化的过程。
那么这个东西可以用map来快速存储,因为map是有序的。而不用写离散化代码(虽然也是两行的事)。这个看看输入范围nlogn一看就知道不会超时啦。
然后对于k人在一段时间[l,r]上机,在l点+k,r+1点-k。求一个前缀和,就能得出所有时间的上机人数了。
而相同人数的最靠前的时间也是在这些点中产生的。
 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(0))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define LL long long
 5 #define mod 1000000007
 6 using namespace std;
 7 const int N=1e5+10;
 8 int T,n,h,p,ct;
 9 LL t1,t2,m,sum,maxn,pt;
10 string s;
11 map<LL,LL>::iterator it;
12 int main()
13 {
14     scanf("%d",&T);
15     while(T--)
16     {
17         scanf("%d",&n);
18         map<LL,LL> num;
19         for(int i=1;i<=n;i++)
20         {
21             scanf("%lld%lld%lld",&t1,&t2,&m);
22             num[t1]+=m;
23             num[t2+1]-=m;
24         }
25         num[0]=0;
26         maxn=0;
27         pt=0;
28         sum=0;
29         for(it=num.begin();it!=num.end();it++)
30         {
31             sum+=it->second;
32             if(sum>maxn)
33             {
34                 maxn=sum;
35                 pt=it->first;
36             }
37         }
38         printf("%lld\n",pt);
39     }
40     return 0;
41 }
View Code

 

 

问题 D: 帅宝宝的xor

时间限制: 2 Sec  内存限制: 128 MB
提交: 43  解决: 10

 

题目描述

众所周知,帅宝宝精通图论。这一天他刚学习了一个新操作-异或(^)。这时候林喵喵给他出了一道异或题:
起初林喵喵给出了一些数字,这些数字均不超过109。
然后林喵喵有以下两种操作:
1 x:在这些数中加入数字x。
2 x:从所有数中找出一个数字y,使得x^y最大,并输出这个y的值。
帅宝宝顿时感到为难,你能帮帅宝宝解决这个问题吗?

 

输入

多组数据(1≤T≤10),对于每组数据:
第一行有一个整数n(0≤n≤105),代表起初的数字个数。
第二行包含n个整数ai(0≤ai≤109),即起初给出的数字个数。
第三行有一个整数q(0≤q≤105),代表接下来的操作个数。
第3+i行的格式如题,其中0≤x≤109。
所有n+q≤2×105。

 

输出

对于每个2操作输出对应的y。
每组数据后空一行。

 

样例输入

3 1 2 3 5 2 1024 1 100 2 1021 2 1022 2 1024

样例输出

3 2 1 100

 

01型字典树模板题。

写过字典树的应该都会,稍难题。

 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define LL long long
 5 #define mod 1000000007
 6 using namespace std;
 7 const int N=1e5+10;
 8 struct Node
 9 {
10     int next[2];
11 };
12 struct Trie
13 {
14     Node node[N*33];
15     int cnt;
16     void init()
17     {
18         cnt=0;
19         clr_1(node);
20     }
21     void add(LL x)
22     {
23         int t,u=0;
24         for(int i=31;i>=0;i--)
25         {
26             t=(x>>i)&1;
27             if(node[u].next[t]==-1)
28             {
29                 node[u].next[t]=++cnt;
30             }
31             u=node[u].next[t];
32         }
33         return ;
34     }
35     LL query(LL x)
36     {
37         int t,u=0;
38         LL ans=0;
39         for(int i=31;i>=0;i--)
40         {
41             t=(x>>i)&1;
42             ans<<=1;
43             if(node[u].next[t^1]==-1)
44             {
45                 ans|=t;
46                 u=node[u].next[t];
47             }
48             else
49             {
50                 ans|=(t^1);
51                 u=node[u].next[(t^1)];
52             }
53         }
54         return ans;
55     }
56 }trie;
57 int n,m,k,t,q;
58 int main()
59 {
60     while(scanf("%d",&n)!=EOF)
61     {
62         trie.init();
63         for(int i=1;i<=n;i++)
64         {
65             scanf("%d",&k);
66             trie.add((LL)k);
67         }
68         scanf("%d",&q);
69         for(int i=1;i<=q;i++)
70         {
71             scanf("%d%d",&t,&k);
72             if(t==1)
73                 trie.add((LL)k);
74             else
75                 printf("%lld\n",trie.query((LL)k));
76         }
77         printf("\n");
78     }
79     return 0;
80 }
View Code

 

问题 E: N马问题

时间限制: 2 Sec  内存限制: 128 MB
提交: 23  解决: 4

 

题目描述

林喵喵和冬冬下象棋的时候突然异想天开,由N数码问题想出了一个N马问题
给出一个n*m的棋盘, 请问至多能放多少个马并使他们无法互相攻击到对方
马可以攻击的地方为所在的坐标横着走一步,竖着走两步,或者横着走两步,竖着走两步
不考虑象棋中马被绊到不能走的规则,即任意马可以走到八个地方(只要那个地方在棋盘内)
 

 

输入

多组数据,请使用读取多组数据的写法
接下来有若干行,每组数据有一行,m和n,表示棋盘是m行n列的,1<=n,m<=1000

 

输出

输出一个数字,表示m*n棋盘最多摆放马的数量

 

样例输入

1 1 5 5 2 3 4 7

样例输出

1 13 4 14
 

找规律题。中等难度题。怎样摆马数量最多?很容易发现一个大棋盘上从左上角摆起,按照2*2放马,2*2不放马,2*2放马.....即(1,1)~(2,2)这个正方形放马,然后其他无论往下还是往右每隔2*2个格子放2*2的马,这样的情况马是最多的。数量为(n*m+1)/2。然而你会发现只有1行和2行的时候(或1列和2列)的时候情况是特殊的,因为他们最多一行正方形或一列正方形,没有和下一列(下一行)共享跳跃到达点。这样的情况需要特殊判断输出相应的答案。
 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4   
 5 int solve(int n, int m) {
 6     if (n < m) return solve(m, n);
 7     else if (m==1) return  n;
 8     else if (m==2) {
 9         return (n/4)*4+((n%4>1)?2:n%4)*2;
10     }
11     else return (n*m+1)/2;
12 }
13   
14 int main() {
15       
16     int r,c;
17     while (scanf("%d%d", &r, &c)!=EOF) {
18         printf("%d\n", solve(r, c));
19     }
20     return 0;
21 }
View Code

 

问题 F: xor game

时间限制: 1 Sec  内存限制: 128 MB
提交: 26  解决: 7

 

题目描述

帅宝宝觉得你们太菜啦,于是帅宝宝用他熟悉的xor操作发明了一个简单的游戏让你们签到,不要辜负他的期望啊。
游戏双方写出他们各自长度为n由互不相同的数字组成的序列(A方)x1,x2,x3……xn和(B方)y1,y2,y3……yn。然后双方同时亮出他们写下的数字序列。如果所有这2n个数字中有相同的数字,则两人进行多次以上步骤,直到这2n个数字中的数字互不相同。这时的数字序列才是游戏所需要的数字序列。
将调整过后的x序列和y序列陈列出来。计算其中满足条件的数字对(i,j)(1≤i,j≤n)的对数。其条件为:计算xi^yj=num后,若num是这2n个数中的一个,则满足条件。
若这样的数字对数为偶数则游戏A方赢,否则B方赢。
现在帅宝宝充当游戏B方,林喵喵充当游戏A方,请你确定在一盘xor游戏中谁会获胜。

 

输入

多组数据(1≤T≤10),对于每组数据:
第一行有一个整数n(1≤n≤105),代表数字序列数字个数。
第二行含n个整数xi(1≤xi≤1017)。
第三行含n个整数yi(1≤yi≤1017)。
保证以上xi和yi这2n个数字互不相等。

 

输出

若帅宝宝获胜输出"shuaibaobao"否则输出"linmiaomiao"。

 

样例输入

3 10 233 322 1234567 7654321 12345678987654321 987654321 23 1 9 10 2 3 4 5 6 7 8 11 12 34 5 1 2 3 4 5 6 7 8 9 10 2 101 10 111 5

样例输出

linmiaomiao linmiaomiao linmiaomiao

提示

 

 xor自反性,b^a^b=a。

 


 

cf上的题,稍难的思维题吧。(毕竟已经写了提示了)。

只不过我把范围改大了,防止你们瞎暴力23333。

首先两个数列内的数都完全不相同。那么任意两个数异或的结果数列内最多只有一个数是对应的。

然后考虑异或的自反性。

如果我们xi^yj==ci(c表示x、y中任意一个数列),那么肯定有xi^ci==yj或者yj^ci==xi。这取决于c是哪个数列。

因此这样的数对是成对出现的,有偶数个。linmiaomiao一定赢。

 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define LL long long
 5 #define mod 1000000007
 6 using namespace std;
 7 const int N=1e5+10;
 8 int n,m,k,t,q,T;
 9 LL x[N],y[N];
10 int main()
11 {
12 //    freopen("10.in","r",stdin);
13 //    freopen("10.out","w",stdout);
14     scanf("%d",&T);
15     while(T--)
16     {
17         scanf("%d",&n);
18         for(int i=1;i<=n;i++)
19             scanf("%lld",&x[i]);
20         for(int i=1;i<=n;i++)
21             scanf("%lld",&y[i]);
22         printf("linmiaomiao\n");
23     }
24     return 0;
25 }
26  
View Code

 

问题G: 旺财的集邮策略

时间限制: 2 Sec  内存限制: 128 MB
提交: 53  解决: 3

 

题目描述

仓鼠旺财有N种不同面值的邮票(如:1 分,3 分),每种邮票都有无限多张。现在旺财想给林喵喵寄信,邮局提供的信封最大只能贴K张邮票。现在旺财想知道它能够从1到M最大可连续贴出的邮资是多少。
例如:假设旺财有1分和3分两种邮票;邮局的信封最多可以贴5张邮票。很容易贴出1到5分的邮资(用1分邮票贴就行了)接下来的邮资也不难:
6 = 3 + 3 
7 = 3 + 3 + 1 
8 = 3 + 3 + 1 + 1 
9 = 3 + 3 + 3 
10 = 3 + 3 + 3 + 1 
11 = 3 + 3 + 3 + 1 + 1 
12 = 3 + 3 + 3 + 3 
13 = 3 + 3 + 3 + 3 + 1
然而,无论如何让5枚1分或者3分的邮票组合,根本不可能贴出14分的邮资。因此,对于这两种不同面值的邮票在最大可以张贴5张的情况下,我们可以最大连续贴出的邮资就是13。
Note:因为14贴不出来,所以最高上限是13而不是15。
我们相信聪明的你一定可以帮助旺财解决问题

 

输入

第1行:
       两个整数,K和N,分别表示最大可以张贴的邮票数量和不同面值的邮票种数。其中K(1 <= K <= 200),N(1 <= N <= 50)
第 2 行: 
       N个整数,分别表示N个不同邮票的面值,每张邮票的面值不超过10000。

 

输出

       一个整数,表示在不超过K张邮票的情况下从1分开始能够最大连续可贴出的邮资是多少。

 

样例输入

5 2 1 3

样例输出

13
 

背包经典问题。开场那两个人太凶残了直接过了。。。
稍难题。
 1 //wanghan's code
 2 #include "iostream"
 3 #include "cstdio"
 4 #include "cstring"
 5 #include "string"
 6 using namespace std;
 7 const int maxn=2e6+100;
 8 const int INF=1<<30;
 9 int K,n;
10 int dp[maxn],v[100];
11 int main()
12 {
13     cin>>K>>n;
14     int ans=0;
15     for(int i=1;i<=n;i++){
16         cin>>v[i];
17         ans=max(ans,v[i]);
18     }
19     int m=2e6;
20     for(int i=1;i<=m;i++)
21         dp[i]=INF;
22     for(int i=1;i<=n;i++){
23         for(int j=v[i];j<=m;j++){
24             dp[j]=min(dp[j],dp[j-v[i]]+1);
25         }
26     }
27     int res=1;
28     for(int i=1;i<=m;i++){
29         if(dp[i]>K){
30             res=i; break;
31         }
32     }
33     cout<<res-1<<endl;
34 }
View Code

 

问题 H: 网络收费

时间限制: 1 Sec  内存限制: 64 MB
提交: 30  解决: 3
 

题目描述

    网络已经成为当今世界不可或缺的一部分。每天都有数以亿计的人使用网络进行学习、科研、娱乐等活动。然而,不可忽视的一点就是网络本身有着庞大的运行费用。所以,向使用网络的人进行适当的收费是必须的,也是合理的。
 
 
 
    假设有这样一个网络:网络中的用户一共有2N个,编号依次为1, 2, 3, …, 2N。这些用户之间是用路由点和网线组成的。用户、路由点与网线共同构成一个满二叉树结构。树中的每一个叶子结点都是一个用户,每一个非叶子结点(灰色)都是一个路由点,而每一条边都是一条网线。
 
 
而网络公司对应该网络的收费方式比较奇特,称为“配对收费”。即对于每两个用户i, j (1≤i < j ≤2N ) 进行收费。
 
 
 
    由于用户可以自行选择两种付费方式A、B中的一种,所以网络公司向学校收取的费用与每一位用户的付费方式有关。该费用等于每两位不同用户配对产生费用之和。 为了描述方便,首先定义这棵网络树上的一些概念:
 
 
 
    祖先:根结点没有祖先,非根结点的祖先包括它的父亲以及它的父亲的祖先;
 
 
 
    管辖叶结点:叶结点本身不管辖任何叶结点,非叶结点管辖它的左儿子所管辖的叶结点与它的右儿子所管辖的叶结点;
 
 
    距离:在树上连接两个点之间的用边最少的路径所含的边数。
   对于任两个用户i, j (1≤i):
 
 
    如果他们最近公共祖先下选择A的人数大于B的人数,那么只对选择A的用户收费,费用为Fi,j(即两人中选择A的有k人,则两人配对收费为k*Fi,j),否则只对选择B的用户收费,费用仍为Fi,j。
 
 
 
    由于最终所付费用与付费方式有关,所以用户们希望能够自行改变自己的付费方式以减少总付费(所有人的付费和)。然而,由于网络公司已经将每个用户注册时所选择的付费方式记录在案,所以对于用户i,如果他/她想改变付费方式(由A改为B或由B改为A),就必须支付Ci元给网络公司以修改档案(修改付费方式记录)。
 
 
 
    现在的问题是,给定每个用户注册时所选择的付费方式以及Ci,试求这些用户应该如何选择自己的付费方式以使得在支付给网络公司的总费用最少(更改付费方式费用+配对收费的费用)。
 
 
 
    注:配对收费并不是说对i结点只选择一个结点与其配对收费,而是对i和所有其他结点都进行配对收费。

 

输入

    输入第一行有一个正整数N。
    第二行有2N个整数,依次表示1号,2号,…,2N号用户注册时的付费方式,每一个数字若为0,则表示对应用户的初始付费方式为A,否则该数字为1,表示付费方式为B。
    第三行有2N个整数,表示每一个用户修改付费方式需要支付的费用,依次为C1, C2, …,CM 。( M=2N ) 以下2N-1行描述给定的两两用户之间的流量表F,总第(i + 3)行第j列的整数为Fi, j+i 。(1≤ i < 2N,1 ≤ j ≤ 2N-i) 所有变量的含义可以参见题目描述。N≤10,0≤Fi, j≤500,0≤Ci≤500 000

 

输出

你的程序只需要向输出文件输出一个整数,表示支付给网络公司的最小总费用。(单位:元)

 

样例输入

2 1 0 1 0 2 2 10 9 10 1 2 2 1 3

样例输出

8

noi2006的原题,某位陈瑜希的论文题。详见我树形dp系列题解。
一道树上背包,也可以多叉转二叉去做。
防ak题,高难度题。
 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define clrmax(x) memset(x,0x3f3f3f3f,sizeof(x))
 5 #define mod 1000000007
 6 #define LL long long
 7 using namespace std;
 8 const int maxN=5e3+10;
 9 int f[maxN][maxN];
10 int flow[maxN][maxN];
11 int c[maxN];
12 int cost[maxN][20],fa[maxN][20];
13 bool chose[maxN];
14 int N,n,m,k,ans,p;
15 int dfs(int u,int dep,int sta)//sta前从右往左第dep+1位开始是该结点分配的B方式的数量,1~dep位为其祖先结点na和nb的大小相对关系,表现为B收费为1,A收费为0。
16 {
17     if(f[u][sta]!=0x3f3f3f3f) return f[u][sta];
18     int num=sta>>dep;
19     int fasta=sta^(num<<dep);
20     //该结点的收费选择chos
21     int chos=(1<<(N-dep))-num>=num?1:0;
22     //叶子结点处理返回
23     if(dep==N)
24     {
25         int v=u-(n-1);
26         fasta<<=1;
27         fasta|=chos;
28         if(num^chose[v])
29             f[u][sta]=c[v];
30         else
31             f[u][sta]=0;
32         for(int i=N;i>=0;i--)
33         {
34             if(!((fasta&1)^num))
35                 f[u][sta]+=cost[v][i];
36             fasta>>=1;
37         }
38         return f[u][sta];
39     }
40     //约束左右结点取B的数量在合理范围内,并选择其中最小的一个和。
41     int minx=max(0,num-(1<<N-dep-1));
42     int maxx=min(num,1<<N-dep-1);
43     for(int i=minx;i<=maxx;i++)
44         f[u][sta]=min(dfs(u<<1,dep+1,(i<<dep+1)|(fasta<<1|chos))+dfs(u<<1|1,dep+1,(num-i<<dep+1)|(fasta<<1|chos)),f[u][sta]);
45     return f[u][sta];
46 }
47 int main()
48 {
49     scanf("%d",&N);
50     n=1<<N;
51     for(int i=1;i<=n;i++)
52     {
53         scanf("%d",&p);
54         chose[i]=p;
55     }
56     for(int i=1;i<=n;i++)
57         scanf("%d",&c[i]);
58     for(int i=1;i<=n;i++)
59         for(int j=i+1;j<=n;j++)
60             scanf("%d",&flow[i][j]);
61     //计算子结点i(树上编号为i+n-1)在深度为j的祖先
62     for(int i=1;i<=n;i++)
63     {
64         k=i+n-1;
65         for(int j=N;j>=0;j--)
66         {
67             fa[i][j]=k;
68             k>>=1;
69         }
70     }
71     clr(cost);
72     //若i,j在深度为k处祖先相同,那末将流量费用flow[i,j]加到i和j在深度k所需要的费用中。
73     for(int i=1;i<=n;i++)
74         for(int j=i+1;j<=n;j++)
75             for(int k=N;k>=0;k--)
76                 if(fa[i][k]==fa[j][k])
77                 {
78                     cost[i][k]+=flow[i][j];
79                     cost[j][k]+=flow[i][j];
80                     break;
81                 }
82     clrmax(f);
83     ans=0x3f3f3f3f;
84     for(int i=0;i<=n;i++)
85         ans=min(ans,k=dfs(1,0,i));
86     printf("%d\n",ans);
87     return 0;
88 }
View Code

 

问题 I: 签到题

时间限制: 5 Sec  内存限制: 16 MB
提交: 241  解决: 18

 

题目描述

众所周知,冬学姐人见人爱,因此他的仰慕者们分布在世界各地。有一天冬学姐心血来潮想要去见他的所有仰慕者。
假设冬学姐所有仰慕者所在城市排成一条直线,总共有n座城市,编号为0,1,2......n-1,从城市i到城市j飞机票所需要的费用为(i+j)%n。而冬学姐刚开始在0号城市中。
因为冬学姐特别喜欢飞机,所以非飞机不搭乘。可是冬学姐囊中羞涩,希望以最少的费用见到他的所有仰慕者。你能帮冬学姐设计一个方案,使得他见到所有仰慕者所需费用最少吗?

 

输入

多组数据,数据不超过1000000组。对于每组数据包含一个整数,代表冬学姐的仰慕者所在城市个数n(0≤n≤1018)。

 

输出

对于每组数据,输出它的数据编号(从1开始),以及冬学姐最少需要的费用。

 

样例输入

0 1 2

样例输出

Case 1: 0 Case 2: 0 Case 3: 1

来源


水题之四。cf上的题。
0号结点独立一组。1和n-1号结点一组,之间建一条边这条边是权值为0(不收费)的。然后是2和n-2,3和n-3....(n+1)/2-1和(n+1)/2(n为奇数)或n/2(n为偶数).这样一共有n/2组之间是不需要收费的。然后0和1,建边,2和n-1建边,3和n-2建边。。这样建n/2条权值为1的边修构成了最终的图。我们只需要花费n/2的费用就能从结点0遍历整个图。
 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define LL long long
 5 #define mod 1000000007
 6 using namespace std;
 7 int main()
 8 {
 9     int kase=0;
10     LL n;
11     while(scanf("%lld",&n)!=EOF)
12         printf("Case %d: %lld\n",++kase,n>>1);
13     return 0;
14 }
View Code

 

问题 J: 水题

时间限制: 1 Sec  内存限制: 128 MB
提交: 11  解决: 2

 

题目描述

是的,这是一道有关流的问题。
给出一个由n个结点组成的有向图,这n个结点标号为0~n-1。
对于任意满足(0≤i<j<n)的结点对(i,j),都存在一条从结点i连向结点j的有向边,其容量为i^j(i异或j)。
请你构建从结点0到结点n-1的最大流网络,并输出其最大流。为简化输出,输出答案 mod 109+7。

 

输入

多组数据,数据不超过10000组。每组数据包含一个整数n,代表有向图结点个数(2≤n≤1018)。

 

输出

对于每组数据,输出它的最大流 mod 109+7后的答案。

 

样例输入

2

样例输出

1
 

 
某网络赛题目。较难难度的找规律题。
运用最大流最小割定理可以推出其规律。当然我当初是打表硬找规律的233333。
 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define LL long long
 4 #define mod 1000000007
 5 using namespace std;
 6 LL quick_pow(LL x, LL n) {
 7     LL res = 1;
 8     x=(x%mod+mod)%mod;
 9     while(n) {
10         if(n&1)
11             res=res*x% mod;
12         n >>=1;
13         x =x*x% mod;
14     }
15     return res;
16 }
17 int main()
18 {
19     LL n,m,q,l,ans,k,kk;
20     int t;
21     while(scanf("%lld",&n)!=EOF)
22     {
23         t=0;
24         n--;
25         m=n;
26         while(m)
27         {
28             t++;
29             m>>=1;
30         }
31         q=1;
32         m=(q<<(t-1));
33         ans=(m%mod)*((1+m)%mod)%mod;
34         ans=ans*quick_pow(2,mod-2)%mod;
35         n-=m;
36         kk=1;
37         k=2;
38         while(k<=n+kk)
39         {
40             ans=(ans%mod+(((n+kk)/k)%mod)*((kk%mod)*(kk%mod)%mod+1)%mod)%mod;
41             if(k==LLONG_MAX)
42                 break;
43             kk=k;
44             k<<=1;
45         }
46         printf("%lld\n",ans);
47     }
48     return 0;
49 }
View Code

 

问题 K: 临界区资源问题

时间限制: 1 Sec  内存限制: 128 MB
提交: 404  解决: 53

 

题目描述

15级有一位李轩大佬,对你没看错就是坐在第二机房的那个。最近正在学操作系统,他遇到了一个问题。可是他今天得来比赛啊,所以没时间解决这个问题,希望你能帮他解决:
在操作系统中,多个进程必须互斥地访问临界区的资源。
简单地说,就是当一个进程A在访问一个临界区资源时,另外一个进程B是不能访问该资源的。
 
考虑有n个临界区资源,编号为0~n-1。刚开始都处于没有进程占用(访问)的空闲状态。
现在顺序地给出m条访问指令,编号1~m(没有退出访问指令,即一旦访问就一直处于访问状态),每个指令只包含一个数k,代表访问的临界区资源编号,并且发出每条指令的进程都互不相同。
如果有某条指令是无效的,即在它之前有其它指令访问该资源,则跳过该条指令,并输出该指令编号。
例如:
n=10,m=10。
m条指令分别是:2 3 5 4 1 2 3 4 5 6。第六条指令访问的2号资源在第一条指令时就被其他进程占用了,同理第七条请求访问的3号资源第二条指令时已经被占用。相同地第八条第九条指令也是无效的。
因此输出6 7 8 9。
好吧说了这么多,其实题意就是:
给出一个长度为m的数列,该数列中数字的取值范围是0~n-1。对于某个位置i有数字ai,如果在i之前出现了和i位置数字ai值相等的数字,则需要输出i。

 

输入

一组数据。
第一行有两个正整数n、m(1≤n,m≤100)。代表资源个数和访问指令个数。
第二行包含m个整数,代表第i条指令访问的资源ai。

 

输出

输出一行,按上升顺序输出无效指令编号。

 

样例输入

10 10 2 3 5 4 1 2 3 4 5 6

样例输出

6 7 8 9

 


 

 

真签到题,比以上水题还水。

就是题目很忽悠23333,然而这是连两个for都能过的题。当初预期是所有写题的人都能过。

然而还是有人纠结前面问题而没看后面问题。导致过题人数只有一半。

 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define LL long long
 5 #define mod 1000000007
 6 using namespace std;
 7 const int N=1e2+10;
 8 int n,m;
 9 int a[N],b[N];
10 int main()
11 {
12     scanf("%d%d",&n,&m);
13     clr(b);
14     for(int i=1;i<=m;i++)
15     {
16         scanf("%d",&a[i]);
17         if(b[a[i]])
18         {
19             printf("%d ",i);
20         }
21         else
22         {
23             b[a[i]]=1;
24         }
25     }
26     printf("\n");
27     return 0;
28 }
View Code

 

posted @ 2017-10-22 21:38  hk_lin  阅读(2204)  评论(2编辑  收藏  举报