题解
今天是暴力局嘛…
第一题——玩具装箱——(toy)
【题目描述】
- 一些玩具从左开始依次装成若干箱,每个箱子只能装最多 M M M个且编号连续的玩具。在某个箱子里装若干个玩具的费用计算方法:如果该箱子里最大的玩具为 a a a,最小的为 b b b,玩具个数为 s s s,则费用为 K + s ∗ ( a − b ) K+s*(a-b) K+s∗(a−b)
- K K K是箱子本身的费用,所有箱子的费用都相等。
- 求最小费用
- 显然可以得出方程 f [ i ] = m i n { f [ j − 1 ] + ( i − j + 1 ) ∗ ( m a x j , i − m i n j , i ) } + K f[i]=min\left\{f[j-1]+(i-j+1)*(max_{j,i}-min_{j,i})\right\}+K f[i]=min{f[j−1]+(i−j+1)∗(maxj,i−minj,i)}+K
- 然后数据很水, O ( n m ) O(nm) O(nm)水过
- 期望得分100,实际得分100
#include <bits/stdc++.h>
#include <stdio.h>
#define LL long long
using namespace std;
void fff(){
freopen("toy.in","r",stdin);
freopen("toy.out","w",stdout);
}
LL read(){
LL x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x;
}
const LL INF=0x3f3f3f3f;
const int N=20100;
const int M=1010;
LL st_max[N][21],st_min[N][21];
LL h[N],a[N],f[N];
LL n,m,k;
LL query_max(int l,int r){
LL kk=h[r-l+1];
return max(st_max[l][kk],st_max[r-(1<<kk)+1][kk]);
}
LL query_min(int l,int r){
LL kk=h[r-l+1];
return min(st_min[l][kk],st_min[r-(1<<kk)+1][kk]);
}
int main(){
// fff();
n=read(),m=read(),k=read();
for(int i=1;i<=n;i++)a[i]=read(),st_max[i][0]=st_min[i][0]=a[i];
for(int i=1;i<=n;i++){
h[i]=h[i-1];
if((1<<(h[i]+1)<=i)) h[i]++;
}
for(int j=1;j<=20;j++){
for(int i=1;i+(1<<j)-1<=n;i++){
st_max[i][j]=max(st_max[i][j-1],st_max[i+(1<<(j-1))][j-1]);
st_min[i][j]=min(st_min[i][j-1],st_min[i+(1<<(j-1))][j-1]);
}
}
memset(f,INF,sizeof(f));
f[0]=0;
for(int i=1;i<=n;i++){
for(int j=max(1ll,i-m+1);j<=i;j++){
f[i]=min(f[i],f[j-1]+k+(i-j+1)*(query_max(j,i)-query_min(j,i)));
}
}
printf("%lld",f[n]);
}
第二题——铁路运费(train)
【题目描述】
- 给出一张n个点m条边的无向图,边权为1,进行Q次操作,每次操作对之后结果有影响
- 每次操作将某一条边的边权加到2
- 问每次操作之后到1的最短路相对于原图有变化的节点有多少
- 显然,这个题暴力分数有50分可以拿。打个暴力绝对不亏!
- 然后,发现每次改变边权就是在删边啊!但是删边不怎么好做
- 那就把这个删边倒过来,变成加边,然后就询问就好了啊…
#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
#define FILENAME "train"
const int MAX_N = 100000;
const int MAX_M = 200000;
vector<int> G[MAX_N];
int dis[MAX_N];
int N,Q;
void bfs_all(int s){
for(int i = 0; i < N; i++) dis[i] = -1;
dis[s] = 0;
queue<int> que;
que.push(s);
while(!que.empty()){
int v = que.front();
que.pop();
for(int i = 0; i < G[v].size(); ++i){
int u = G[v][i];
if(dis[u] != -1 && dis[u] <= dis[v] + 1) continue;
dis[u] = dis[v] + 1;
que.push(u);
}
}
}
bool ok[MAX_N];
vector<int> G2[MAX_N];
int bfs(int u, int v){
if(dis[u] == dis[v])return 0;
if(dis[u] > dis[v]) swap(u, v);
G2[u].push_back(v);
int res = 0;
if(ok[u]){
queue<int> que;
que.push(v);
while(!que.empty()){
int v = que.front();
que.pop();
if(ok[v]) continue;
ok[v] = true;
res++;
for(int i = 0; i < G2[v].size(); ++i){
int u = G2[v][i];
que.push(u);
}
}
}
return res;
}
int M,qs[MAX_M],us[MAX_M],vs[MAX_M],ord[MAX_M];
bool used[MAX_M];
void init(){
for(int i = 0; i < M; ++i)used[i] = false;
for(int q = 0; q < Q; ++q){
ord[q] = qs[q];
used[qs[q]] = true;
}
int c = Q;
for(int i = 0; i < M; ++i)
if(!used[i])
ord[c++] = i;
}
int cnt[MAX_M + 1];
int main(){
// freopen(FILENAME ".in", "r", stdin);
// freopen(FILENAME ".out", "w", stdout);
scanf("%d%d%d", &N, &M, &Q);
for(int i = 0; i < M; ++i){
scanf("%d%d", us + i, vs + i);
us[i]--; vs[i]--;
G[us[i]].push_back(vs[i]);
G[vs[i]].push_back(us[i]);
}
bfs_all(0);
for(int q = 0; q < Q; ++q){
scanf("%d", qs + q);
qs[q]--;
}
init();
int prv = 0;
ok[0] = true;
cnt[M] = 0;
for(int i = M - 1; i >= 0; --i){
int u = us[ord[i]], v = vs[ord[i]];
int cur = bfs(u, v);
cnt[i] = prv + cur;
prv = cnt[i];
}
for(int q = 0; q < Q; ++q)
printf("%d\n", N - 1 - cnt[q + 1]);
return 0;
}
第三题——模式(patterns)
【题目描述】
- 给出一段序列,求出最长的出现次数超过k的相同的子串
- 这个暴力hash+map
- 期望得分100
#include <bits/stdc++.h>
#include <stdio.h>
#define LL long long
#define ull unsigned long long
using namespace std;
void fff(){
freopen("patterns.in","r",stdin);
freopen("patterns.out","w",stdout);
}
int read(){
int x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x;
}
const int N=21000;
const ull base1=233;
int n,k;
int a[N],nxt[N];
ull Hash[N],Pow[N];
ull HASH(int l,int len){
int r=l+len-1;
return Hash[r]-Hash[l-1]*Pow[r-l+1];
}
map<ull,int> mp;
bool solve(int len){
mp.clear();
for(int i=1;i+len-1<=n;i++){
ull tt=HASH(i,len);
mp[tt]++;
if(mp[tt]>=k) return true;
}
return false;
}
int main(){
// fff();
n=read(),k=read();
for(int i=1;i<=n;i++) a[i]=read();
for (int i=1;i<=n;i++) Hash[i]=Hash[i-1]*base1+a[i];
Pow[0]=1;
for (int i=1;i<=n;i++) Pow[i]=Pow[i-1]*base1;
if(n<=40){
for(int len=n-1;len>=1;len--){
for(int begin=1;begin+len-1<=n;begin++){
ull tar=HASH(begin,len);int cnt=0;
for(int i=begin+1;i+len-1<=n;i++){
if(HASH(i,len)==tar) cnt++;
if(cnt>=k-1){
printf("%d",len);
return 0;
}
}
}
}
}else{
int l=1,r=n-1;
int ans;
while(l<=r){
int mid=(l+r)>>1;
if(solve(mid)) l=mid+1,ans=mid;
else r=mid-1;
}
// while(!solve(l)) l--;
printf("%d",ans);
}
}