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,你现在要求修改数量最少的元素,使得这个数列严格递增.其中无论是修改前还是修改后,每个元素都必须是整数.请输出最少需要修改多少 ...
随机推荐
- 手机自动化测试:Appium源码分析之跟踪代码分析九
手机自动化测试:Appium源码分析之跟踪代码分析九 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家 ...
- .NET中数据访问方式(一):LINQ
语言集成查询(Language-Integrated Query),简称LINQ,.NET中的LINQ体系如下图所示: 在编程语言层次,LINQ对于不同的数据源提供了相同的查询语法,方便了程序员操 ...
- jquery的冒泡事件event.stopPropagation()
js中的冒泡事件与事件监听 冒泡事件 js中“冒泡事件”并不是能实际使用的花哨技巧,它是一种对js事件执行顺序的机制,“冒泡算法”在编程里是一个经典问题,冒泡算法里面的冒泡应该 说是交换更加准确:js ...
- 变态版大鱼吃小鱼-基于pixi.js 2D游戏引擎
之前用CSS3画了一条
- 网站与域名知识扫盲-DNS
域名概述 域名的概念 IP地址不易记忆 早期使用Hosts解析域名 主机名称重复 主机维护困难 DNS(Domain Name System 域名系统) 分布式 层次性 域名空间结构 根域 组织域[. ...
- JS为网页添加文字水印【原创】
最近需要实现为网页添加水印的功能,由于水印的信息是动态生成的,而百度谷歌上的方法往往都是为网页添加图片水印或为图片添加水印,而为网页添加文字水印相关资料较少,于是就自己动手写了这个代码. 通常加动态水 ...
- 【HDOJ 1086】 模板水过
You can Solve a Geometry Problem too Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/3 ...
- 每天一个linux命令(63):Linux中zip压缩和unzip解压缩命令详解
文章转自:http://www.jb51.net/LINUXjishu/105916.html 1.把/home目录下面的mydata目录压缩为mydata.zipzip -r mydata.zip ...
- 使用Block传值
使用Block的地方很多,其中传值只是其中的一小部分,下面介绍Block在两个界面之间的传值: 先说一下思想: 首先,创建两个视图控制器,在第一个视图控制器中创建一个UILabel和一个UIButto ...
- 详解常用的gulp命令
gulp.js是一款自动化构建工具,我们经常使用它在开发过程自动执行常见的任务.gulp.js 是基于 Node.js 构建的,利用 Node.js,可以快速构建项目. 由于gulp使用基于node, ...