安徽大学第九届大学生程序设计竞赛 网络预选赛

A. 成功人士
Time Limit: 1000 ms   Memory Limit: 64 MB
Total Submission: 250   Submission Accepted: 76
Description
学校里共有n个学生,m门课,如果某个学生在某门课中拿到了最高分(可以是并列),则这个学生是成功人士。现在给出n个学生的m门课的成绩,问有多少个成功人士。

Input
第一行,一个整数t,表示测试数据组数,(1<=t<=100)
对于每组测试数据,第一行两个整数,n和m,(1<=n,m<=50)
接下来n行,每一行有m个数字(中间不分隔),表示这个学生每门课的成绩,其中成绩为1-9的整数。

Output
每组测试数据,一个整数,表示有多少个成功人士。

Sample Input
Original Transformed
2
3 3
223
232
112
3 5
91728
11828
11111

Sample Output
Original Transformed
2
3


上代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
using namespace std;
int success[100];
struct stu{
    int num;
    int core;
};
bool cmp(stu a,stu b){
    return a.core >b.core;
}
int main(){
     int t,m,n,i,j;
     stu students[100];
     char a[100][100];
     cin>>t;
     while(t--){
        int ans=0;
        memset(success,0,sizeof(success));
        cin>>n>>m;
        for(i=0;i<n;i++){
            getchar();
            scanf("%s",a[i]);
        }
        for(i=0;i<m;i++){
            for(j=0;j<n;j++){
                students[j].core=(int)a[j][i]-'0';
                students[j].num=j;
            }
            sort(students,students+n,cmp);//排列 
            for(j=0;j<n;j++){
                success[students[j].num]=1;
                if(students[j+1].core!=students[j].core)
                break;
            }//并列的全都标记 
        } 
        for(i=0;i<n;i++){
            if(success[i]==1)
            ans++;
        } 
        cout<<ans<<endl;
     }
      
}


PS(转):

题解

取出每个人每门课的成绩,排序后找出最大的几个,然后将他们的编号插入到 set 里
最后计算 set 的元素数量即可

#include <iostream>
#include <cstring>
#include <set>
#include <algorithm>
using namespace std;
const int maxn = 55;
char score[maxn][maxn];
set<int> ans;
struct Node{
    int n;
    int w;
    Node(int a=-1,int b=-1):n(a),w(b){}
    bool operator < (const Node &rhs)const{
        return w > rhs.w;
    }
}node[maxn];
int main(){
    #ifdef debug
    freopen("in.txt", "r", stdin);
    int START = clock();
    #endif
    cin.tie(0);
    cin.sync_with_stdio(false);
    
    int T;
    cin >> T;
    
    while(T--){
        ans.clear();
        int n,m;
        cin >> n >> m;
        for(int i=0;i<n;i++)
            cin >> score[i];
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++)
                node[j] = Node(j,score[j][i]);
            sort(node,node+n);
            int t = node[0].w;
            for(int j=0;j<n;j++){
                if(t == node[j].w)
                    ans.insert(node[j].n);
                else
                    break;
            }
        }
        cout << ans.size() << endl;
    }
    #ifdef debug
    printf("Time:%.3fs.\n", double(clock() - START) / CLOCKS_PER_SEC);
    #endif
    return 0;
}




B. 迭代归一
Time Limit: 1000 ms   Memory Limit: 64 MB
Total Submission: 323   Submission Accepted: 74
Description
我们把一个正整数的每一位上的数字加起来,得到新的数字,我们把这样的一次操作称为一次迭代变换。直到这个数字只有一位数。
如,9876经过一次变换成为9+8+7+6=30,经过第二次变换成为3+0=3,结束。
那么9876就经过了两次迭代变换。如今给一个正整数,问需要迭代变换多少次后会停止。

Input
一个整数t,表示测试数据组数(1<=t<=100)。
对于每组测试数据,只有一行,表示一个正整数,正整数最多有100000位。

Output
输出若干行,每行对应每组数据需要迭代变换的次数

Sample Input
Original Transformed
3
2
10
99999999

Sample Output
Original Transformed
0
1
2

上代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
using namespace std;
int main(){
    char a[100010];
     int t,n,flag,ans;
     long long int sum;
     cin>>t;
     while(t--){
        sum=0;
        ans=0;
        flag=0;
        scanf("%s",a);
        sum+=(int)a[0]-'0';
        for(int i=1;a[i]>='0' && a[i]<='9';i++){
            sum+=(int)a[i]-'0';
            if(flag==0){
                flag=1;
                ans++;
             }
         }
          
         while(sum>=10){
            cout<<ans<<" "<<sum<<endl;
            n=sum;
            sum=0;
            while(n>0){
                sum+=n%10;
                n/=10;
             }
             ans++;
         }
         cout<<ans<<" "<<sum<<endl;
         cout<<ans<<endl;
     }
     return 0;
}


PS(转):

#include <iostream>
#include <cstring>
using namespace std;
 
const int maxn = 100005;
char s[100005];
int main(){
    #ifdef debug
    freopen("in.txt", "r", stdin);
    int START = clock();
    #endif
    cin.tie(0);
    cin.sync_with_stdio(false);
     
    int T; 
    scanf("%d",&T);
    while(T--){
        int ans = 0;
        scanf("%s",s);
        int size = strlen(s);
        int n = 0;
        bool flag = false;
        for(int i = 0;i < size;i++){
            n += s[i]-'0';
            if(flag)
                ans=1;
            if(!flag && s[i] - '0' > 0)
                flag = true;
        }
        while(n>=10){
            ans++;
            int t = 0;
            while(n){
                t += n%10;
                n /= 10;
            }
            n = t;
        }
        printf("%d\n",ans);
    }
 
    #ifdef debug
    printf("Time:%.3fs.\n", double(clock() - START) / CLOCKS_PER_SEC);
    #endif
    return 0;
}



C. 置换的魔术
Time Limit: 1000 ms   Memory Limit: 64 MB
Total Submission: 452   Submission Accepted: 30
Description
有n个正整数,其中1到n的正整数出现且只出现一次的序列,称为1-n的一个排列。
如1,2,3和3,1,2都是1-3的排列,但是1,3,3不是1-3的排列。
如今,给n个数,问最少修改几个数,可以使得序列成为1-n的一个排列。

Input
一个整数t,表示测试数据的组数,(1<=t<=210)
对于每一组测试数据,第一行为一个整数n,(1 <= n <= 500)
第二行有n个整数a1,a2,……an,空格分隔,(ai为任意的32位有符号正整数)。

保证多组数据中的n的和不超过100000。

Output
每组测试数据,输出一个整数,表示最少修改几个数。

Sample Input
Original Transformed
2
5
1 3 2 4 5
6
1 1 1 1 1 1

Sample Output
Original Transformed
0
5

上代码:

/*怎么看都觉得坑,按下面解题者的意思来说就是,测试数据量和题目给的不一样,数组得开大一点,难怪我的总是runtime error,一个同学数组开到100000+10,通过了*/


  
  
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
using namespace std;
int vis[510];//这里如果开到100000+10,应该就通过了
int main(){
      int t,n,ans;
      long long int x;
      cin>>t;
      while (t--){
         ans=0;
         memset (vis,0, sizeof (vis));
         cin>>n;
         for ( int i=0;i<n;i++){
             cin>>x;
             if (x<=n && x>0) //显然,题目如果给的n值超过500,runtime error就能解释了
             vis[x]=1;
          }
          for ( int i=1;i<=n;i++){
             if (!vis[i])
               ans++;
          }
         cout<<ans<<endl;
      }
      return 0;
}


ps(转):

题解

思路应该很容易,不过数据比较坑
用一个数组来记录 1-n 的数字哪个已经读入过了
没有读入的就是要交换的

这道题数据量和题目给的不一样
开大一点能解决

另外可以使用 set 来保存
只要是 1-n 的数字,直接扔到 set 里
最后 n-s.size() 即可

数字存在负数,因此读入的判断两侧都要判断

#include <cstdio>
#include <iostream>
#include <cstring>
#include <set>
using namespace std;
int main(){
    #ifdef debug
    freopen("in.txt", "r", stdin);
    int START = clock();
    #endif
    cin.tie(0);
    cin.sync_with_stdio(false);
    
    int T;
    scanf("%d",&T);
    while(T--){
        set<int> s;
        s.clear();
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            int t;
            scanf("%d",&t);
            if(t <= n && t >= 1)
                s.insert(t);
        }
        printf("%d\n",n-s.size());
    } 
    #ifdef debug
    printf("Time:%.3fs.\n", double(clock() - START) / CLOCKS_PER_SEC);
    #endif
    return 0;
}


D. 买买买
Time Limit: 1000 ms   Memory Limit: 64 MB
Total Submission: 286   Submission Accepted: 56
Description
一天Alice打开了她日常玩的游戏,发现她里面还有n个游戏币,她想把这些游戏币花光。
现在可以买的一共三种道具,分别是房子(每一个价值1234567个游戏币),车子(每一个价值123456个游戏币),电脑(每一个价值1234个游戏币)。
现在她想知道,通过买这三种道具是否可以把n个游戏币全部花光。

Input
第一行,一个数字t(1<=t<=100)。代表测试数据数量。
对于每一组测试数据,一个整数n(1<=n<=1000000000),代表现在的游戏币。

Output
输出n行,每行输出"YES"或者"NO",表示她可以或者不可以把游戏币全部花光。

Sample Input
Original Transformed
2
1359257
17851817

Sample Output
Original Transformed
YES
NO

上代码:

/*这题我没写出来,因为金额太大,本想用背包的,结果开不了那么大的数组~~~~~~,看看人家的吧*/

ps(转):

题解

由于最大的值非常大,如果直接 dfs 会非常慢
而且打表的文件会非常大

而看 1234567 和 1000000000 其实差别不是很大
除一下发现最多也就能买 800 多套房子
而即使全部买成汽车也就能买 8000 多辆
乘起来的数据量只有 10e6 完全是可以遍历的
也就是说,只需要枚举房子和车的数量,然后判断剩下的钱能不能整除电脑

这样做不超时的原因是房子和车的价格都非常大,可以将许多数据“跨越”掉
如果这数都很小的话,就没有办法了

#include<bits/stdc++.h>
using namespace std;
int main() {
	int T;
	cin >> T;
	while(T--) {
		int n;
		cin >> n;
		int flag = 0;
//		int a = n/1234567;
//		int b = n/123456;
		for(int i = 0 ; i <= n/1234567 ; i ++) {
			for(int j = 0 ; j <= n/123456 ; j ++) {
				if(n >= i*1234567 + j*123456){
					int cur = n - i*1234567 - j*123456;
					if(cur % 1234 == 0){
						flag = 1;
//						goto tt;
						break;
					}
				}
			}
			if(flag)
				break;
		}
//		tt:
		if(flag)
			cout << "YES" << endl;
		else
			cout << "NO" << endl;
	}
	return 0;
}



E. FJ的旅行
Time Limit: 1000 ms   Memory Limit: 64 MB
Total Submission: 34   Submission Accepted: 2
Judge By Case
Description
每当西瓜的朋友来西瓜家看他,西瓜总是喜欢带他们逛自己的豪宅。西瓜的豪宅有N幢楼(1<=N<=1000),用1到N的整数编号。1号楼是西瓜豪宅的大门,N号楼是西瓜的储藏室。西瓜的豪宅里总共有M条道路(1<=M<=10000)。每条道路连接两栋不同的楼房,道路的长度不超过35000。
为了最好地炫耀他的豪宅,西瓜准备从大门出发,经过一些楼房到达储藏室,再经过一些楼房回到自己的大门。
他要求他的路径越短越好,但是不能经过任意一条道路多于一次。请你计算这样的一条最短路径。西瓜保证这样的路径是存在的。

Input
第一行:N和M
第2..M+1行:每行三个整数表示一条道路(起点,终点,长度)

Output
一个整数,表示最短路径长度

Sample Input
Original Transformed
4 5
1 2 1
2 3 1
3 4 1
1 3 2
2 4 2

Sample Output
Original Transformed
6

上代码:

/*这题我还是没写出来,这次比较有水平的一题~~~~~~,看看人家的吧*/

PS(转):

题解

本次最难的一题
要求是对于一个无向图,在每条路只走一次的情况下,从起点到终点再返回起点的最短路
看到最短路,很容易就想到 BFS ,由于每条路有一定的权值,因此需要用 Dijkstra

很显然的思路,而且能通过样例
但是如果仔细分析样例就能发现有很大的问题存在

可以很容易看出来,去的时候最短路是 3
回来的时候最短路也是 3

但是,如果单纯只是删掉第一次最短路途径的边去跑第二次最短路,有可能就会出现问题
比如,如果第一次最短路走的是 1-2-3-4 这条路,那么第二次时压根就无法返回起点

也就是说,存在有多个最短路有重边的情况
这个问题导致了单纯的搜是不行的

图论问题,不会不如试下网络流

套用网络流的概念来分析下试试

  • 最短路 = 最小费用
  • 每个边一次 = 流量为1

看上去好像没有问题,再深入分析下
最小费用的是 最小费用最大流
它求的是在所有最大流中费用最小的

那么我们先要限定流量
由于每个边只能走一次,边的流量显然是 1
如何体现去回两次呢?
可以在建一个源点,这个源点往外的流量为 2 ,将它连在起点或终点上,然后跑它到另一个点的最小费用最大流

由于其他点的流量都是 1 ,这个节点往外的流量是 2 ,因此只要有解,最大流必然为 2
此时建的图已经和题意的图存在一些差别了
可以看作从起点走两条完全不同的路(每条路的流量为 1 )到终点(汇点流量为 2 )

建图完毕,套用模板

匡斌的模板里点的编号是 0~n-1
因此加边的时候要把 u 和 v 分别减去 1
初始化的时候记得加上汇点

输出最小的费用即可

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <queue>
#include <set>
#include <algorithm>
using namespace std;
const int MAXN = 1005; 
const int MAXM = 10005; 
const int INF = 0x3f3f3f3f; 
struct Edge { 
    int to,next,cap,flow,cost; 
}edge[MAXM]; 
int head[MAXN],tol; 
int pre[MAXN],dis[MAXN]; 
bool vis[MAXN]; 
int N;//节点总个数,节点编号从0~N-1 
void init(int n){ 
    N = n; 
    tol = 0; 
    memset(head,-1,sizeof(head)); 
} 
void addedge(int u,int v,int cap,int cost) { 
    edge[tol].to = v; 
    edge[tol].cap = cap; 
    edge[tol].cost = cost; 
    edge[tol].flow = 0; 
    edge[tol].next = head[u]; 
    head[u] = tol++; 
    edge[tol].to = u; 
    edge[tol].cap = 0; 
    edge[tol].cost = -cost; 
    edge[tol].flow = 0; 
    edge[tol].next = head[v]; 
    head[v] = tol++; 
} 
bool spfa(int s,int t) { 
    queue<int>q; 
    for(int i = 0;i < N;i++) { 
        dis[i] = INF; 
        vis[i] = false; 
        pre[i] = -1; 
    } 
    dis[s] = 0; 
    vis[s] = true; 
    q.push(s); 
    while(!q.empty()){ 
        int u = q.front(); 
        q.pop(); 
        vis[u] = false; 
        for(int i = head[u]; i != -1;i = edge[i].next){ 
            int v = edge[i].to; 
            if(edge[i].cap > edge[i].flow && 
               dis[v] > dis[u] + edge[i].cost ){ 
                dis[v] = dis[u] + edge[i].cost; 
                pre[v] = i; 
                if(!vis[v]){ 
                    vis[v] = true; 
                    q.push(v); 
                } 
            } 
        } 
    } 
    if(pre[t] == -1)return false; 
    else return true; 
} 
//返回的是最大流,cost存的是最小费用 
int minCostMaxflow(int s,int t,int &cost) { 
    int flow = 0; 
    cost = 0; 
    while(spfa(s,t)){ 
        int Min = INF; 
        for(int i = pre[t];i != -1;i = pre[edge[i^1].to]){ 
            if(Min > edge[i].cap - edge[i].flow) 
                Min = edge[i].cap - edge[i].flow; 
        } 
        for(int i = pre[t];i != -1;i = pre[edge[i^1].to]){ 
            edge[i].flow += Min; 
            edge[i^1].flow -= Min; 
            cost += edge[i].cost * Min; 
        } 
        flow += Min; 
    } 
    return flow; 
} 
int main(){
    #ifdef debug
    freopen("in.txt", "r", stdin);
    int START = clock();
    #endif
    cin.tie(0);
    cin.sync_with_stdio(false);
    int n, m;
    while(cin>>n>>m){
    init(n+1);
    for(int i=0;i<m;i++){
        int u,v,cost;
        cin >> u >> v >> cost;
        addedge(u-1,v-1,1,cost);
        addedge(v-1,u-1,1,cost);
    }
    addedge(n-1,n,2,0);
    int ans=0;
    minCostMaxflow(0,n,ans);
    cout << ans << endl;
    }
    #ifdef debug
    printf("Time:%.3fs.\n", double(clock() - START) / CLOCKS_PER_SEC);
    #endif
    return 0;
}




F. 周末大法好
Time Limit: 1000 ms   Memory Limit: 64 MB
Total Submission: 318   Submission Accepted: 116
Description
在火星上,每年有x天。惊奇的是,和地球上一样,火星上也是有星期的概念的,连续的5天工作日,然后连续的2天周末。他们只有周末放假。
现在你的任务是,确定火星上每年可能的最少放假的天数和最多放假的天数。

Input
第一行,一个数字n。代表测试数据数量。
接下来n行,每行一个整数x (1<=x<=1,000,000),代表火星每年有x天。

Output
输出n行,每行两个整数。代表火星上每年可能的最少放假的天数和最多放假的天数。

Sample Input
Original Transformed
2
14
2

Sample Output
Original Transformed
4 4
0 2

上代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
using namespace std;
long long int n,Max,Min;
int main(){
     int t;
     cin>>t;
     while(t--){
        Max=0;
        Min=0;
        cin>>n;
        Max+=n/7*2;
        Min+=n/7*2;
        if(n%7==6){
            Max+=2;
            Min+=1;
        }
        else if(n%7>=2){
            Max+=2;
        }
        else if(n%7==1){
            Max+=1;
        }
        cout<<Min<<" "<<Max<<endl;
    }
     return 0;
}



G. 交换大法好
Time Limit: 1000 ms   Memory Limit: 64 MB
Total Submission: 158   Submission Accepted: 31
Description
有一天,天上掉馅饼了。不过不是直接掉馅饼,是告诉你你将要得到的馅饼的数量a。聪明的你得到了一种魔法,可以在整数a中交换任意两个相邻的数字。而这种魔法,你最多只能使用k次。你使用魔法操作a,得到的最大的结果就是你最终获得的馅饼数量。

你最多可以获得的馅饼数量是多少呢?

Input
第一行,一个数字n(1<=n<=60)。代表测试数据数量。
接下来n行,每行两个整数a和k(1<=a<=1,000,000,000; 0<=k<=100)。

Output
输出n行,每行一个整数,代表你最多使用魔法k次,可以得到的最大的数字。

Sample Input
Original Transformed
2
1990 1
1034 2

Sample Output
Original Transformed
9190
3104

上代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<vector>
using namespace std;
int main(){
    int t,i,j,k,p,max;
    string a;
    char temp;
    cin>>t;
    while(t--){
        cin>>a;
        getchar();
        cin>>k;
        for(i=0;i<a.length();i++){
            p=i;
            max=(int)a[i];
            for(j=i+1;j<a.length() && j-i<=k;j++){
                if((int)a[j]>max){
                    p=j;
                    max=(int)a[j];
                }
            }
            temp=a[p];
            for(j=p;j>i;j--){
                a[j]=a[j-1];
            }
            a[i]=temp;
            k=k-(p-i);
        }
        cout<<a<<endl;
    }
}



H. 今年多少岁
Time Limit: 1000 ms   Memory Limit: 64 MB
Total Submission: 478   Submission Accepted: 112
Description
小明出生于1937年7月7日,问对于给定的日期,小明几周岁了,不足一周年的部分可以忽略。

注意:1938年7月6日,小明0周岁,1938年7月7日小明1周岁,同理1939年7月6日,小明1周岁,1939年7月7日,小明2周岁。

Input
一个整数t(1<=t<=100),表示数据组数
对于每组测试数据,三个整数,逗号隔开,分别表示给定日期的年、月、日。给定的日期保证合法, 而且一定是小明出生后的日期,且小明的岁数保证在100以内。

Output
对于每一组数据,输出一个整数,表示小明的周岁数。

Sample Input
Original Transformed
2
1938 7 6
1938 7 7

Sample Output
Original Transformed
0
1

上代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
using namespace std;
int a[3];
int main(){
     int t,ans;
     cin>>t;
     while(t--){
        cin>>a[0]>>a[1]>>a[2];
        ans=0;
        if(a[0]>=1937){
            ans+=a[0]-1938;
            if(a[1]>7 || (a[1]==7 && a[2]>=7))
            ans++;
         }
         cout<<ans<<endl;
    }
     return 0;
}


总结:这次网络赛做出来五题,C题如果题目数据给的没问题,应该能过六题的,剩下E题真不会,D题呢,哎,脑子转一转,其实数据给的意思可能就是让我暴力解决的。木啊!!!看别人代码也是一种是成长,尤其像我这种自己代码写得跟狗啃的一样,更应该多看看各路大神是怎么码代码的。

介绍一个不错的博客 :http://www.biyisi.cn/archives/date/2017/03


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值