本来这一场报了名准备打的,但是因为下午跟队友打了一场训练联盟太累了就没打了。赛后重现了下,感觉还行,先写A~C的题解,后面的明天再看看,补得动在更新。(啊还要补训练联盟题。。。)
A:
题意:给你一个n*m的方格,每条边为墙,为你至少打通几个墙能使任意方格的人走到外面去。
思路:没什么思路。。。一眼就看出来答案就是n*m,
B:
题意:给你一个n个数的序列,问你能否求出非负数m,c,其中A[i]=(A([i-1]+c) mod m,如果m可以无限大就输出0,其中A[1]=s mod m(s题目中说明了一定是非负的)。
思路:通过观察可以发现A[i]=A[i-1]+c或者A[i]=A[i-1]+c-m。其次,如果每个数相等我们可以令c=0,m趋于无限大即可,那答案就输出0。再者,如果每相邻两个数的差相等(等差数列),我们令c=1,m趋于无限大即可,那答案就输出0。通过模拟下样例我们可以发现,如果有答案,那么相邻两个数做差的结果只有两种,如果只有一种答案或者整个序列只有一个数那m可以无限大答案就是0,否则答案一定为-1。所以接下来只要讨论相邻两个数做差的结果的情况了:1、通过A[i]的两种函数式我们可知,当A[i]<=m时,c就等于后一项减一项,那么我们求出c后就可以通过找到序列A中的最大值和它后面的那个值代入到上述第二个表达式求出m。2、通过1其实可以看出,c就是做差结果中最大值,m就是c-做差结果的最小值(最小值是负的)。所以通过上面分析,要想有结果那么做差结果的最小值minn要是负数,做差结果的最大值maxn要是正数,maxn-minn>=序列中的最大值maxx,否则输出-1。分析完毕(可能分析的还是有点繁琐)
代码:
#include <bits/stdc++.h> #define INF 0x3f3f3f3f using namespace std; const int N =1e5+5; int vis[N],a[N]; int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int t; cin >> t; while(t--) { set<int>s;//用set去存做差的结果可以达到自动去重的效果 int n; cin >> n; int maxx=-INF; for(int i=1;i<=n;i++) cin >> a[i],maxx=max(maxx,a[i]);//找到序列的最大值 for(int i=2;i<=n;i++) s.insert((a[i]-a[i-1])); if(s.size()>2) {//做差结果种数大于2,找不到这样的m和c cout << -1 << endl; continue; } if(s.size()==1) {//等差数列,m可无限大 cout << 0 << endl; continue; } if(n<=2) {//对应上面分析做差只有一种结果和整个序列只有一个数 cout << 0 << endl; continue; } int minn=*s.begin(),maxn=*(--s.end());//找到做差的结果的最大值和最小值 //cout << minn << " " << maxn << endl; if(minn<0&&maxn>0&&(maxn-minn)>=maxx)//有答案的前提 { cout << maxn-minn << " " << maxn << endl; } else cout << "-1" << endl; } return 0; }C:
题意:你有n个朋友,你要玩m天,每天有k个朋友可选择但只能选一个朋友,而且每个朋友被选择次数不能超过m/2(向上取整),输出满足条件下每天应该选哪位朋友,如果找不到输出NO。
思路:通过分析易得,只有每一次选朋友只有一个朋友可以选且该朋友选的次数大于m/2(向上取整),结果才会是-1。否则无论如何都可以安排朋友陪自己玩且每个朋友被选的次数满足题目中要求。那么每一次只有一个朋友可以选是必须输出的,剩下每次有多种可以选我们只要优先选哪个朋友被选次数少即可,用一个cnt数组统计下每个朋友选了几次即可。
代码:
#include <bits/stdc++.h> using namespace std; const int N = 1e5+5; vector<int>v[N];//用v[i][j]表示第i天第j个朋友的编号,其中v[i].size()表示第i天有多少个朋友可以选择 int cnt[N];//用来统计每个朋友要选几次 int main() { int t; cin >> t; while(t--) { int n,m; cin >> n >> m; int flag=0;//标记每次只有一个朋友可以选择且该朋友被选次数大于m/2向上取整 for(int i=1;i<=m;i++) { int k; cin >> k; for(int j=1;j<=k;j++) { int x; cin >> x; v[i].push_back(x); } if(k==1)//因为这一天只有一个朋友可以选,那这天必须选这个朋友,所以先把这种情况处理,被选次数++ { cnt[v[i][0]]++; } if(cnt[v[i][0]]>(m+1)/2)//判断一下当前朋友被选次数是否超过题目中要求 { flag=1; } } if(flag) {//有朋友被选次数超过了m/2向上取整。 cout << "NO" << endl; for(int i=1;i<=m;i++) v[i].clear();//初始化,建议大家在每次输入前进行初始化,我就因为这里wa一次 memset(cnt,0,sizeof(cnt)); flag=0; continue; } cout << "YES" << endl; for(int i = 1; i <= m; i++) { int maxn=v[i][0];//先把第i天第一个朋友取出来 if(v[i].size()==1) //如果这一天只有一个朋友可以选直接输出即可 { cout << v[i][0] << " "; continue; } for(int j=1;j<v[i].size();j++)//以及与当前被选出来的朋友后面的朋友比较他们被选择的次数 { if(cnt[maxn]>cnt[v[i][j]])//最优结果肯定是选当前被选择次数较少的朋友 { maxn=v[i][j]; } } cnt[maxn]++;//该朋友被选,次数++ cout << maxn << " "; } cout << endl << endl; for(int i=1;i<=m;i++) v[i].clear();//初始化,建议在开头初始化,这样避免写两遍,减少代码量 memset(cnt,0,sizeof(cnt)); flag=0; } return 0; }