2017年中国大学生程序设计竞赛-中南地区赛暨第八届湘潭市大学生计算机程序设计大赛题解&源码(A.高斯消元,D,模拟,E,前缀和,F,LCS,H,Prim算法,I,胡搞,J,树状数组)
A------------------------------------------------------------------------------------
题目链接:http://202.197.224.59/OnlineJudge2/index.php/problem/read/id/1260
题解:随机 n 个数把矩阵补全成 n × n 的。那么就是要算伴随矩阵的第一行,也就是逆矩阵的第一列,高斯消元即可。
源码:(Q神写的高斯消元,先贴一下诶,待补)
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=;
const int Mod=;
int a[MAXN][MAXN],b[MAXN][MAXN];
int get_rand(int x)//[0,x)
{
int t=;
while((<<t)<x)t++;
int res=x;
while(res>=x)
{
res=;
for(int i=;i<t;i++)
res|=(rand()%)<<i;
}
return res;
}
int fp(int a,int k)
{
int res=;
while(k)
{
if(k&)res=1LL*res*a%Mod;
a=1LL*a*a%Mod;
k>>=;
}
return res;
}
void solve(int n)
{
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
b[i][j]=(i==j);
int det=;
for(int i=;i<=n;i++)
{
int t=i;
for(int k=i;k<=n;k++)
if(a[k][i])t=k;
if(t!=i)det*=-;
for(int j=;j<=n;j++)
{
swap(a[i][j],a[t][j]);
swap(b[i][j],b[t][j]);
}
det=1LL*a[i][i]*det%Mod;
int inv=fp(a[i][i],Mod-);
for(int j=;j<=n;j++)
{
a[i][j]=1LL*inv*a[i][j]%Mod;
b[i][j]=1LL*inv*b[i][j]%Mod;
}
for(int k=;k<=n;k++)
{
if(k==i)continue;
int tmp=a[k][i];
for(int j=;j<=n;j++)
{
a[k][j]=(a[k][j]-1LL*a[i][j]*tmp%Mod+Mod)%Mod;
b[k][j]=(b[k][j]-1LL*b[i][j]*tmp%Mod+Mod)%Mod;
}
}
}
det=(det+Mod)%Mod;
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
b[i][j]=1LL*det*b[i][j]%Mod;
}
int main()
{
srand(time(NULL));
int n;
while(scanf("%d",&n)!=EOF)
{
for(int j=;j<=n;j++)
a[][j]=;
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
scanf("%d",&a[i][j]);
solve(n);
for(int i=;i<=n;i++)
printf("%d%c",(i& ? b[i][] : (Mod-b[i][])%Mod)," \n"[i==n]);
}
return ;
}
B------------------------------------------------------------------------------------------
题目链接:http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1261
题解:考虑 Kruskal 的过程,肯定是同样权值的边连通了一个点集。如果要让 MST 变大,就是要让某个权值的边不再连通。这是全局最小割问题,可以网络流也可以用 Stoer–Wagner 算法。
C------------------------------------------------------------------------------------------
题目链接:http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1262
题解:
D------------------------------------------------------------------------------------------
题目链接:http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1263
题解:将n*m的照片放大a*b倍,然后直接输出,此题只要模拟即可
源码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,m,a,b;
while(cin>>n>>m>>a>>b)
{
string s[];
for(int i=;i<n;i++)
{
cin>>s[i];
}
for(int i=;i<n*a;i++)
{
for(int j=;j<m*b;j++)
{
cout<<s[i/a][j/b];
}
cout<<endl;
}
}
return ;
}
E-------------------------------------------------------------------------------
题目链接:http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1264
题解:
我的理解是:
题意:选取一段区间求和取绝对值,加在初始化为0的数值上,选了的区间不能再选,问最大的和是多少
解法:前缀和排序,最大和最小相减加起来就好了
源码:
#include<bits/stdc++.h>
#define INF 1000000000
#define ll long long
using namespace std;
ll x[];
ll sum;
int main()
{
std::ios::sync_with_stdio(false);
ll n,m,a,b;
while(cin>>n>>m>>a)
{
sum=;
ll ans[];
ans[]=;
for(int i=;i<=n;i++)
{
ll num;
cin>>num;
ans[i]=ans[i-]+num;
}
ll cnt=;
ll Max=;
Max=max(Max,sum);
sort(ans,ans++n);
while(m--)
{
ll Pmax=ans[n--];
ll Pmin=ans[cnt++];
// cout<<Pmax<<" "<<Pmin<<endl;
sum+=abs(Pmax-Pmin)-a;
if(abs(Pmax-Pmin)-a<) break;
Max=max(Max,sum);
}
cout<<Max<<endl;
}
return ;
}
F-------------------------------------------------------------------------------
题目链接:http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1265
题解:首先对 a 离散化,之后可以 O(n^3 ) 枚举序列 X.如果之后用 O(n) 的 LCS dp 会使复杂度变成 O(n^4 ).
std 用的方法是 2^3 枚举 X 的一个子序列,通过预处理一个next(i,c) 表示 i 位置后 c 字符第一次出现的位置,来 O(1) 判断是否是 A 的子序列。
某位学长的理解:
将a数组离散化,枚举三元素,n^3
求LCS,花费n*3,现在总体复杂度是n^4的
求LCS这步可以 优化,我们预处理吃nex[i][c],当前i位置后面第一个c在哪里
就可以在2^3下O(1)求出LCS了
有个坑的地方就是 a[i]可能会大于m,wa了很久
源码:(来自某位学长)
#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
const long long INF = 1e18+1LL;
const double Pi = acos(-1.0);
const int N = 2e2+, M = 1e3+, mod = 1e9+,inf = 2e9; LL n,m,a[N],c,b[N],nex[N][N];
LL v[N];
LL f[N];
LL query(LL x) {
return lower_bound(b+,b+c+,x) - b;
}
int main() {
while(scanf("%lld%lld",&n,&m)!=EOF) {
for(int i = ; i <= n; ++i)
scanf("%lld",&a[i]),b[i] = a[i];
sort(b+,b+n+);
c = unique(b+,b+n+) - b - ;
for(int i = c; i >= ; --i) {
if(b[i] > m) c--;
else break;
}
for(int i = ; i <= ; ++i) f[i] = ;
for(int i = ; i <= n; ++i) a[i] = query(a[i]);
memset(nex,,sizeof(nex));
memset(v,,sizeof(v)); for(int i = ; i <= n; ++i) {
for(int j = ; j <= c; ++j) {
for(int k = i+; k <= n; ++k) {
if(a[k] == j) {
nex[i][j] = k;
break;
}
}
}
} for(int i = ; i <= c; ++i) v[i] = ; v[c+] = m - c; for(int i = ; i <= c+; ++i) {
for(int j = ; j <= c+; ++j) {
for(int k = ; k <= c+; ++k) { int fi = , se = , th = ; for(int C = ; C < ; ++C) {
int now = ;
if(C&()) {
if(!nex[now][i]) {continue;}
else now = nex[now][i];
}
if(C&()) {
if(!nex[now][j]) {continue;}
else now = nex[now][j];
}
if(C&()) {
if(!nex[now][k]) {continue;}
else now = nex[now][k];
} if(C == ) fi = ;
else if(C == || C == || C == ) se = ;
else if(C)th = ; } if(fi){
f[] += v[i]*v[j]*v[k];
}
else if(se) {
f[] += v[i]*v[j]*v[k];
}
else if(th) {
f[] += v[i]*v[j]*v[k];
}
else {
f[] += v[i]*v[j]*v[k];
} }
}
} for(int i = ; i < ; ++i) cout<<f[i]<<" ";
cout<<f[]<<endl; }
return ;
} F
G-------------------------------------------------------------------------------
题目链接:http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1266
题解:括号序列就是要求前 (2k + 1) 个里面至少要有 k 个左括号。那么先把所有括号翻成右括号,之后重新翻回左括号。
那么从左到右贪心,用一个堆维护现在可以翻回左括号的位置。每次相当于加两个当前段的字符,取一个最小的。所以事件只有最小的被拿完了,或者当前段拿完了。模拟即可。
H--------------------------------------------------------------------------------
题目链接:http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1267
题解:按照 Prim 算法计算生成树。假设初始点 v 0 是某条直径的端点。那么距离 v 0 最远的 v 1 必然是直径的另一个端点。
又因为距离任意点最远的要么是 v 0 要么是 v 1 ,所以剩下的点只需要连往 v 0 和 v 1 中较远的一个即可。
我的理解:
题意:要把所有的边都联通,并要求权值之和最大
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int inf=(<<);
const int maxn=;
ll pos;
ll n,ans,vis[maxn],in[maxn];
vector<pair<int,int>>e[maxn];
ll sum;
void dfs(int v,ll cnt)
{
if(ans<cnt)
{
ans=cnt;
pos=v;
}
if(vis[v])return;
vis[v]=;
for(int i=; i<e[v].size(); i++)
// cout<<e[v][i].first;
if(!vis[e[v][i].first])
dfs(e[v][i].first,cnt+e[v][i].second);
}
ll dis1[],dis2[];
void DFS(int v,ll cnt,ll dis[])
{
if(vis[v]) return;
vis[v]=;
dis[v]=cnt;
for(int i=; i<e[v].size(); i++)
// cout<<e[v][i].first;
if(!vis[e[v][i].first])
DFS(e[v][i].first,cnt+e[v][i].second,dis);
}
int main()
{
int n,m;
ans=;
while(~scanf("%d",&n))
{
ans=;
memset(dis1,,sizeof(dis1));
memset(dis2,,sizeof(dis2));
memset(in,,sizeof(in));
memset(vis,,sizeof(vis));
for(int i=;i<=n;i++)
{
e[i].clear();
}
for(int i=; i<n; i++)
{
ll u,v,w;
scanf("%d%d%d",&u,&v,&w);
e[u].push_back({v,w});
e[v].push_back({u,w});
}
dfs(,);
ll cnt=ans;
ans=;
memset(vis,,sizeof(vis));
ans=;
DFS(pos,,dis1);
memset(vis,,sizeof(vis));
ans=;
dfs(pos,); memset(vis,,sizeof(vis));
DFS(pos,,dis2);
memset(vis,,sizeof(vis));
ll cot=ans;
//cout<<cot<<" "<<cnt<<endl;
ll Max=max(cnt,cot);
//cout<<Max<<endl;
sum=;
for(int i=;i<=n;i++)
{
sum+=max((ll)dis1[i],(ll)dis2[i]);
}
printf("%lld\n",sum-Max);
}
return ;
}
I----------------------------------------------------------------------------------
题目链接:http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1268
题解:
陷阱:此题好像用lld不会过,要用int64,我也不知道啥情况QAQ
源码:
#include <bits/stdc++.h>
using namespace std;
__int64 gcd(__int64 a,__int64 b)
{
return b==?a:gcd(b,a%b);
}
int main()
{
__int64 n,m;
while(scanf("%I64d%I64d",&n,&m)!=EOF)
{
printf("1/%I64d\n",n*m/gcd(n,m)*);
}
return ;
}
J-----------------------------------------------------------------------------------
题目链接:http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1269
题解:
源码:(来自某位学长)
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
using namespace std; typedef long long ll;
typedef double db; const int mod=; int t,n,m;
int A[],B[];
int dp[][][];
int a[][][]; int lowbit(int x)
{
return x&(-x);
} void add(int id,int bd,int x,int v)
{
while(x)
{
a[id][bd][x]+=v;
if(a[id][bd][x]>=mod) a[id][bd][x]-=mod;
if(a[id][bd][x]<) a[id][bd][x]+=mod;
x-=lowbit(x);
}
} int sum(int id,int bd,int x)
{
int res=;
while(x<=m)
{
res+=a[id][bd][x];
if(res>=mod) res-=mod;
x+=lowbit(x);
}
return res;
} int main()
{
#ifdef Haha
//freopen("in.in","r",stdin);
#endif // Haha
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=; i<=n; i++) scanf("%d",&A[i]);
for(int i=; i<=m; i++) scanf("%d",&B[i]);
memset(dp,,sizeof(dp));
memset(a,,sizeof(a));
if(A[]==) add(,m,m,);
else add(,,m,);
for(int i=; i<=n; i++)
{
for(int j=; j<=m; j++)
{
for(int k=; k<=m; k++)
{
dp[i][j][k]=sum(i,k,B[j]);
//printf("%d %d %d %d\n",i,j,k,dp[i][j][k]);
}
if(i==) continue;
for(int k=; k<=m; k++)
{
if(dp[i-][j][k]==) continue;
int L,R;
if(A[i-]==) L=B[j],R=k;
else L=k,R=B[j];
if(L>R) continue; if(A[i]==)
{
add(i,R,R,dp[i-][j][k]);
add(i,R,L-,-dp[i-][j][k]);
}
else
{
add(i,L,R,dp[i-][j][k]);
add(i,L,L-,-dp[i-][j][k]);
}
}
}
}
int ans=;
for(int i=; i<=m; i++)
{
for(int j=; j<=m; j++)
{
ans+=dp[n][i][j];
if(ans>=mod) ans-=mod;
}
}
printf("%d\n",ans);
}
return ;
}
2017年中国大学生程序设计竞赛-中南地区赛暨第八届湘潭市大学生计算机程序设计大赛题解&源码(A.高斯消元,D,模拟,E,前缀和,F,LCS,H,Prim算法,I,胡搞,J,树状数组)的更多相关文章
- ACM-ICPC 2018 徐州赛区网络预赛 H Ryuji doesn't want to study (树状数组差分)
https://nanti.jisuanke.com/t/31460 题意 两个操作.1:查询区间[l,r]的和,设长度为L=r-l+1, sum=a[l]*L+a[l+1]*(L-1)+...+a[ ...
- st表树状数组入门题单
预备知识 st表(Sparse Table) 主要用来解决区间最值问题(RMQ)以及维护区间的各种性质(比如维护一段区间的最大公约数). 树状数组 单点更新 数组前缀和的查询 拓展:原数组是差分数组时 ...
- HDU3792---Twin Prime Conjecture(树状数组)
Twin Prime Conjecture Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Ot ...
- 【BZOJ3529】数表(莫比乌斯反演,树状数组)
[BZOJ3529]数表(莫比乌斯反演,树状数组) 题解 首先不管\(A\)的范围的限制 要求的东西是 \[\sum_{i=1}^n\sum_{j=1}^m\sigma(gcd(i,j))\] 其中\ ...
- BZOJ2141 排队 树状数组 分块
原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ2141.html 题目传送门 - BZOJ2141 题意 给定一个序列 $a$ ,先输出原先的逆序对数. ...
- 【树状数组】【P3902】 递增
传送门 Description 给你一个长度为\(n\)的整数数列,要求修改最少的数字使得数列单调递增 Input 第一行为\(n\) 第二行\(n\)个数代表数列 Output 输出一行代表答案 H ...
- hdu1166 敌兵布阵(树状数组)
敌兵布阵 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submi ...
- Bzoj 1901: Zju2112 Dynamic Rankings 主席树,可持久,树状数组,离散化
1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 6321 Solved: 2628[Su ...
- HDU 5256 - 序列变换 ,树状数组+离散化 ,二分法
Problem Description 我们有一个数列A1,A2...An,你现在要求修改数量最少的元素,使得这个数列严格递增.其中无论是修改前还是修改后,每个元素都必须是整数.请输出最少需要修改多少 ...
随机推荐
- 自动化利器-RPM自定义打包
1.Rpm打包程序 1.1为什么要使用rpm打包 1.编译安装软件,优点是可以定制化安装目录.按需开启功能等,缺点是需要查找并实验出适合的编译参数,诸如MySQL之类的软件编译耗时过长. 2.yum安 ...
- C#研究OpenXML之路(1-新建工作簿文件)
一.写在开头 一直想沉下心来研究研究OpenXML编程,可是由于公司编程项目一笔接一笔,很难静下来,所以一直是采用的COM操作Excel.现在终于得闲,特将心得历程记录下来. 今天的第一个实例代码是来 ...
- Excel图表-"DNA"图
p{ font-size: 15px; } .alexrootdiv>div{ background: #eeeeee; border: 1px solid #aaa; width: 99%; ...
- 性能调优之Java系统级性能监控及优化
性能调优之Java系统级性能监控及优化 对于性能调优而言,通常我们需要经过以下三个步骤:1,性能监控:2,性能剖析:3,性能调优 性能调优:通过分析影响Application性能问题根源,进行优化 ...
- struts2自定义日期类型转换器
在java web表单中提交的数据难免会有日期类型,struts2支持的日期类型是yyyy-MM-dd,如果是其他格式,就需要自己进行转换.比如yy-MM-dd 要完成自己定义的转换需要完成. 主要的 ...
- 你的计算机也可以看懂世界——十分钟跑起卷积神经网络(Windows+CPU)
众所周知,如果你想研究Deep Learning,那么比较常用的配置是Linux+GPU,不过现在很多非计算机专业的同学有时也会想采用Deep Learning方法来完成一些工作,那么Linux+GP ...
- vue-router2 使用
VUE-ROUTER2 API http://router.vuejs.org/zh-cn/api/router-link.html 1,安装vue-router npm install vue ...
- 使用gulp编译sass
之前写了一篇在ruby环境下如何编译sass的文章:<css预处理器sass使用教程(多图预警)>,随着现在前端构建工具的兴起,也学着使用这些工具来编译sass.webpack存在一个CS ...
- FarPoint.Win.Spread 自定义表头
最近C/S项目中用到FarPoint.Win.Spread,想在表头加个全选的checkbox,实现效果如图: 列的设置大家都清楚,直接可视化视图中设置该列CellType为CheckBox类型即 ...
- 为linux安装xen-tools提示/dev/xvdd does not exist
看样子百度还是不如google啊.百度上找到的信息完全无用.google上却给我找到了... 1:当/dev/xvdd does not exist错误出现时,可以尝试下 mount /dev/cdr ...