A diffsum
链接:http://code.bupt.edu.cn/problem/contest/115/problem/A/
大致题意:给你一个数列,取出任意两项求其差的绝对值,求所有组合的绝对值的和。
思路:刚开始写了一个暴力枚举的方法,想水一水试试,结果意料之中的Tle了,其复杂度是n^2,之后想了一个nlogn的方法就是先对数组进行排序(降序),在求出第一项和其他所有项的组合,之后的项的组合其实和前面的项的和差了一个(n-i)*(a[i-1]-a[i]),有了这个就可以快速的求出所有项的和了。
code:
#include <iostream>
#include <cstring>
#include <cstdlib>
#include<cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#define INF 1000000000
#define eps 0.001
using namespace std;
const int MAX_N=100005;
const int MAX_V=10010;
const int MAX_Q=60020;
int a[MAX_N];
bool cmp(int a,int b)
{
return a>b;
}
int main()
{
long long sum,mid;
int n;
while(scanf("%d",&n)!=EOF){
for(int i=0;i<n;i++) scanf("%d",&a[i]);
sort(a,a+n,cmp);
sum=0;
mid=0;
for(int i=1;i<n;i++) mid+=(a[0]-a[i]);
sum+=mid;
for(int i=1;i<n;i++){
mid-=(a[i-1]-a[i])*(n-i);
sum+=mid;
}
printf("%lld\n",sum);
}
return 0;
}
B 小妹妹送很多快递
链接:http://code.bupt.edu.cn/problem/p/474/
大致题意:求图上两点之间的最小最大权值边的总和,当时一直感觉是上次spfa的一个巧妙的转化,但是怎么都想不出来,中间考虑过并查集但是没有往深的地方想,哎白白我浪费了那么长的时间。
思路:其实就是最小生成树,将并查集的高度改成区域所占有节点的个数,枚举边当两条边不在同一集合的时候,则一个集合的点和另一个集合相连的最小最大权值边就是当前的这条边,所以此时有,注意零的情况注意开long long此题可过
res+=(long long)e.cost*num[pu]*num[pv]*2;
code:
#include <iostream>
#include <cstring>
#include <cstdlib>
#include<cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#define INF 1000000000
#define eps 1e-6
using namespace std;
const int MAX_V=10005;
const int MAX_E=100010;
const int MAX_Q=10000005;
int par[MAX_V],num[MAX_V];
bool vis[MAX_V];
void init(int n)
{
for(int i=0;i<=n;i++){
par[i]=i;
num[i]=1;
}
}
int Find(int x)
{
if(par[x]==x) return par[x];
else return par[x]=Find(par[x]);
}
void unite(int x,int y)
{
x=Find(x);
y=Find(y);
if(x==y) return ;
if(num[x]<num[y]){
par[x]=y;
num[y]+=num[x];
}
else{
par[y]=x;
num[x]+=num[y];
}
}
bool same(int x,int y)
{
if(Find(x)==Find(y)) return true;
else return false;
}
struct edge{int u,v,cost;} Es[MAX_E];
bool cmp(edge A,edge B)
{
return A.cost<B.cost;
}
int V,E;
int krustal()
{
sort(Es,Es+E,cmp);
init(V);
long long res=0;
int pu,pv;
for(int i=0;i<E;i++){
edge e=Es[i];
if(!same(e.u,e.v)){
pu=Find(e.u);
pv=Find(e.v);
if(!e.cost) e.cost++;
res+=(long long)e.cost*num[pu]*num[pv]*2;
unite(e.u,e.v);
}
}
printf("%lld\n",res);
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&V,&E);
for(int i=0;i<E;i++) scanf("%d%d%d",&Es[i].u,&Es[i].v,&Es[i].cost);
krustal();
}
return 0;
}
C 新来的小妹妹
链接:http://code.bupt.edu.cn/problem/p/477/
思路:后缀数组+高度数组的模板题
code:
#include <iostream>
#include <cstring>
#include <cstdlib>
#include<cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#define INF 1000000000
#define eps 1e-6
using namespace std;
string S,T;
const int MAX_V=100000;
const int MAX_N=100005;
const int MAX_L=100005;
int sa[MAX_L],lcp[MAX_L];
int n,k;
int high[MAX_N+1];
int tmp[MAX_N+1];
bool compare_sa(int i,int j)
{
if(high[i]!=high[j]) return high[i]<high[j];
else{
int ri=i+k<=n? high[i+k]:-1;
int rj=j+k<=n? high[j+k]:-1;
return ri<rj;
}
}
void construct_sa(string S,int *sa)
{
n=S.length();
for(int i=0;i<=n;i++){
sa[i]=i;
high[i]=i<n?S[i]:-1;
}
for(k=1;k<=n;k*=2){
sort(sa,sa+n+1,compare_sa);
tmp[sa[0]]=0;
for(int i=1;i<=n;i++){
tmp[sa[i]]=tmp[sa[i-1]]+(compare_sa(sa[i-1],sa[i])?1:0);
}
for(int i=0;i<=n;i++){
high[i]=tmp[i];
}
}
}
void construct_lcp(string S,int *sa,int *lcp)
{
int n=S.length();
for(int i=0;i<=n;i++) high[sa[i]]=i;
int h=0;
lcp[0]=0;
for(int i=0;i<n;i++){
int j=sa[high[i]-1];
if(h>0) h--;
for(;j+h<n&&i+h<n;h++){
if(S[j+h]!=S[i+h]) break;
}
lcp[high[i]-1]=h;
}
}
void solve()
{
int s1=S.length();
construct_sa(S,sa);
construct_lcp(S,sa,lcp);
int ans=0;
for(int i=0;i<S.length();i++) ans=max(ans,lcp[i]);
printf("%d\n",ans);
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
cin>>S;
solve();
}
return 0;
}
D 学妹去搬砖
链接:http://code.bupt.edu.cn/problem/p/476/
思路:当时直接套的模板其实现在还是不太明白,等我再消化消化吧。
code:
#include <iostream>
#include <cstring>
#include <cstdlib>
#include<cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#define INF 1000000000
#define eps 1e-6
using namespace std;
const int MAX_N=15;
const int MAX_M=15;
const int M=1000000007;
int dp[2][1<<MAX_M];
int n,m,k;
bool color[MAX_N][MAX_M];
void solve()
{
int *crt=dp[0];
int *next=dp[1];
crt[0]=1;
for(int i=n-1;i>=0;i--){
for(int j=m-1;j>=0;j--){
for(int used=0;used<1<<m;used++){
if((used>>j&1)||color[i][j]){
next[used]=crt[used&~(1<<j)];
}
else{
int res=0;
if(j+1<m&&!(used>>(j+1)&1)&&!color[i][j+1]){
res+=crt[used|1<<(j+1)];
}
if(i+1<n&&!color[i+1][j]){
res+=crt[used|1<<j];
}
next[used]=res%M;
}
}
swap(crt,next);
}
}
printf("%d\n",crt[0]);
}
int main()
{
int x,y;
while(scanf("%d%d%d",&n,&m,&k)!=EOF){
memset(color,false,sizeof(color));
for(int i=0;i<k;i++){
scanf("%d%d",&x,&y);
color[x][y]=true;
}
memset(dp,0,sizeof(dp));
solve();
}
}