- 南京網絡賽
A
題意:一個蛇形矩陣,每個數美麗值等於十進制各位的權值相加,標記一些點,每次問一個矩陣內美麗值之和
思路:可以通過根據x,y推出被標記的點數值,再利用二維偏序按x排序,樹狀數組維護y。每次查詢爲二維平面的矩陣差分。
代碼:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(ll i=0;i<n;i++)
#define for1(i,n) for(ll i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const ll maxn = 2e6+5;
const ll maxm = 1e6+5;
ll n,m,mm;
ll ans[maxm];
struct Q{
ll x,y,id,flag,v;
}q[maxm<<1];
bool cmp(Q a,Q b){
if(a.x==b.x) {
if(a.y==b.y) return a.id<b.id;
return a.y<b.y;
}
return a.x<b.x;
}
struct BIT{
ll node[maxn];
ll lb(ll x){return x&(-x);}
void init(){forn(i,maxn)node[i] = 0;}
void update(ll pos,ll v){for(ll i = pos;i<=n;i+=lb(i))node[i]+=v;}
ll ask(ll pos){ll sum = 0;for(ll i = pos;i;i-=lb(i))sum+=node[i];return sum;}
ll query(ll l,ll r){return ask(r)-ask(l-1);}
}bit;
ll func(ll x,ll y)
{
x=n+1-x;
y=n+1-y;
ll ans;
ll mi=min(x,min(y,min(n-x+1,n-y+1)));
if(x<=y) ans=1ll*mi*(1ll*4*(n-1)-4*mi)+1ll*10*mi-4*n-3+x+y;
else ans=1ll*mi*(4*n-4*mi)+1ll*2*mi+1-x-y;//模擬過程
ll tot=0;
while (ans)
{
tot+=ans%10;
ans/=10;
}
return tot;
}
void init(){
bit.init();
forn(i,maxm) ans[i] = 0;
forn(i,maxm<<1) q[i] = {0,0,0,0,0};
}
int main(){
IO;
ll t;cin>>t;
while(t--){
cin>>n>>m>>mm;
init();
ll cnt = 0;
forn(i,m){
ll x,y;cin>>x>>y;
ll z = func(x,y);
q[cnt++] = {x,y,0,0,z};//x,y,id,flag,v
}
forn(i,mm){
ll x,y,xx,yy;cin>>x>>y>>xx>>yy;
q[cnt++] = {xx,yy,i,1,0};
if(x>1&&y>1) q[cnt++] = {x-1,y-1,i,1,0};
if(x>1) q[cnt++] = {x-1,yy,i,-1,0};
if(y>1) q[cnt++] = {xx,y-1,i,-1,0};
}
sort(q,q+cnt,cmp);
forn(i,cnt){
if(q[i].flag==0) bit.update(q[i].y,q[i].v);
else ans[q[i].id] += bit.ask(q[i].y)*q[i].flag;
}
forn(i,mm) cout<<ans[i]<<'\n';
}
return 0;
}
H
題意:有向圖,有負權值邊,新添加給定兩點的邊,使得圖中沒有負環,且添加邊權儘可能小。
思路:spfa
代碼:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int inf = 0x3f3f3f3f;
const int maxn = 305;
int d[maxn],vis[maxn];
vector<pair<int,int> >e[maxn];
void init(){
forn(i,maxn) e[i].clear();
}
int spfa(int s,int t){
forn(i,maxn) vis[i] = 0,d[i] = inf;
queue<int>q;
q.push(t);d[t] = 0;
while(!q.empty()){
int u = q.front();q.pop();
vis[u] = 0;
for(auto x:e[u]){
int v = x.first,w = x.second;
if(d[v]>d[u]+w){
d[v] = d[u]+w;
if(!vis[v]){
q.push(v);
vis[v] = 1;
}
}
}
}
e[s].push_back({t,-d[s]});
return -d[s];
}
int main(){
IO;
int t;cin>>t;
while(t--){
init();
int n,m;cin>>n>>m;
forn(i,m){
int u,v,w;cin>>u>>v>>w;
e[u].push_back({v,w});
}
forn(i,6){
int s,t;cin>>s>>t;
cout<<spfa(s,t)<<'\n';
}
}
return 0;
}
- 徐州
B
題意:1e9個點,1e5次操作,a:可讓一個點永久失效,b:查詢一個點往後最近的有效點。
思路:並查集,unorderd_map
代碼:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(itn i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
unordered_map<int,int> mp;
int find(int x){
return mp.count(x)?mp[x] = find(mp[x]):x;
}
int main(){
IO;
int n,q;cin>>n>>q;
while(q--){
int op,x;cin>>op>>x;
if(op==1) mp[x] = x+1;
else cout<<find(x)<<'\n';
}
return 0;
}
D.
模擬kmp板子
代碼:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int maxn = 1e5+5;
int nex[maxn],nex2[maxn];
void getnex(string &s){
int len = s.size(),i = 0,j = -1;
nex[0] = -1;
while(i<len){
if(s[i]==s[j]||j==-1) nex[++i] = ++j;
else j = nex[j];
}
}
void getnex2(string &s){
int len = s.size(),i = 0,j = -1;
nex2[0] = -1;
while(i<len){
if(s[i]==s[j]||j==-1) nex2[++i] = ++j;
else j = nex2[j];
}
}
bool kmp(string &s,string &m){
int len = s.size(),len2 = m.size(),i =0,j = 0;
while(i<len){
if(s[i]==m[j]||j==-1) i++,j++;
else j = nex[j];
if(j==len2) return 1;
}
return 0;
}
bool kmp2(string &s,string &m){
int len = s.size(),len2 = m.size(),i =0,j = 0;
while(i<len){
if(s[i]==m[j]||j==-1) i++,j++;
else j = nex2[j];
if(j==len2) return 1;
}
return 0;
}
int main(){
IO;
string s;cin>>s;
getnex(s);
int n,len = s.size();cin>>n;
forn(i,n){
string m;cin>>m;
int len2 = m.size();
if(len==len2){
if(kmp(m,s)) cout<<"jntm!"<<'\n';
else cout<<"friend!"<<'\n';
}else if(len>len2){
getnex2(m);
if(kmp2(s,m)) cout<<"my child!"<<'\n';
else cout<<"oh, child!"<<'\n';
}else{
if(kmp(m,s)) cout<<"my teacher!"<<'\n';
else cout<<"senior!"<<'\n';
}
}
return 0;
}
G.
題意:一個字符串,1e5. 查詢所有子串滿足迴文串的情況下ans+=不同字符數,求總ans
思路:馬拉車,算每個字符串對半徑的貢獻
代碼:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int maxn = 3e5+5;
const int inf = 2e9;
string s;
char ma[maxn<<1];
int mp[maxn<<1],last[26];
void manacher(string &s,int len){
int p = 0,r = 0,mid = 0;
ma[p++] = '$',ma[p++] ='#';
forn(i,len) ma[p++] = s[i],ma[p++] = '#';
forn(i,p){
mp[i] = r>i?min(mp[(mid<<1)-i],r-i):1;
while(ma[i+mp[i]]==ma[i-mp[i]]) mp[i]++;
if(i+mp[i]>r) r = i+mp[i],mid = i;
}
}
int main(){
IO;
cin>>s;
forn(i,26) last[i] = -inf;
int len = s.size();
manacher(s,len);
len = (len+1)<<1;
ll res = 0;
for(int i = 2;i<len;i++){
bool ok = 0;
int now = i-2>>1;
if(ma[i]!='#') last[ma[i]-'a'] = i,ok = 1;
if(ok){
int lim = mp[i]+1>>1;
forn(j,26){
if(last[j]==-inf) continue;
int l = last[j]-2>>1;
if(now-l+1<=lim) res+=lim-now+l;
}
}
else{
int lim = mp[i]>>1;
if(!lim) continue;
forn(j,26){
if(last[j]==-inf) continue;
int l = last[j]-2>>1;
if(now-l+1<=lim) res+=lim-now+l;
}
}
}
cout <<res<<'\n';
return 0;
}
I題
題意:給一個1e5n的全排列數組,查詢1e5段區間滿足min(a[i],a[j])==gcd(a[i],a[j])的個數(i,j在區間內)
思路:共有nlogn對,之後二維偏序,找x,y的右下角。排序y,用樹狀數組維護x,更新答案。
代碼:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int maxn = 1e5+5;
int a[maxn],pos[maxn],ans[maxn],n,m;
struct Q{
int x,y,id;
}q[maxn*20];
bool cmp(Q a,Q b){
if(a.y==b.y){
return a.id<b.id;
}
return a.y<b.y;
}
struct BIT{
ll node[maxn];
ll lb(ll x){return x&(-x);}
void init(){forn(i,maxn)node[i] = 0;}
void update(ll pos,ll v){for(ll i = pos;i<=n;i+=lb(i))node[i]+=v;}
ll ask(ll pos){ll sum = 0;for(ll i = pos;i;i-=lb(i))sum+=node[i];return sum;}
ll query(ll l,ll r){return ask(r)-ask(l-1);}
}bit;
int main(){
IO;
cin>>n>>m;
for1(i,n){
cin>>a[i];
pos[a[i]] = i;
}
int cnt = 0;
for(int i = 1;i<=n;i++){
for(int j = i+i;j<=n;j+=i){
int l = pos[i],r = pos[j];
// cerr<<i<<' '<<j<<' '<<l<<' '<<r<<'\n';
q[cnt++] = {min(l,r),max(l,r),-1};
}
}
forn(i,m){
int l,r;cin>>l>>r;
q[cnt++] = {l,r,i};
}
sort(q,q+cnt,cmp);
forn(i,cnt){
//cerr<<"!@#!@#!@# "<<q[i].x<<' '<<q[i].y<<' '<<q[i].id<<'\n';
if(q[i].id==-1) bit.update(q[i].x,1);
else ans[q[i].id] = bit.query(q[i].x,q[i].y);
}
forn(i,m) cout<<ans[i]<<'\n';
return 0;
}
/*
9 10
5 2 8 3 9 6 7 1 4
1 2
1 6
1 5
5 8
2 9
4 8
7 6
2 8
9 9
8 9
0
4
2
3
13
6
0
10
0
1
*/
M
題意:兩個字符串,求用第一個構造出字典序大於第二個字符串的最長子序列。
思路:模擬,有點坑,沒搞懂字典序,注意判斷最後一位。
代碼:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int inf = 2e9+5;
const int maxn = 1e6+5;
int a[maxn][26];
int main(){
IO;
int n,m;cin>>n>>m;
string s,mm;cin>>s>>mm;
//if(s==mm) return cout<<n-1<<'\n',0;
//int n = s.size(),m = mm.size();
forn(i,26) a[n][i] = inf;
for(int i = n-1;i>=0;i--){
forn(j,26) a[i][j] = a[i+1][j];
a[i][s[i]-'a'] = i;
}
ll now = 0,j = 0,ans = -1;
while(now<n){
int x = mm[j]-'a',p = inf;
for(int i = x+1;i<26;i++){
p = min(p,a[now][i]);
}
ans = max(ans,n-p+j);
if(a[now][x]>=p)break;
if(j==m-1){
// cerr<<"!@#"<<now<<' '<<j+n-a[now][x]<<'\n';
if(a[now][x]+1!=n) ans = max(ans,j+n-a[now][x]);
//else ans = max(ans,j+n-a[now][x]);
break;
}
now = a[now][x]+1;
j++;
}
cout << ans<<'\n';
return 0;
}
- 南昌網路賽
B. 題意n個點,m條邊的無向帶權圖,現在有一個超人在s點,和k個消防隊在ki個點,超人的速度是消防隊的c倍。求超人到達所有點的最短時間中取最大值,消防隊到達所有點的最短時間中取最大值,求誰更快。快的一方輸出最短路長度(不是最短時間)
思路:然後建一個新點可以走到所有消防隊,求最短路。
代碼:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int maxn = 1005;
const int inf = 2e9+5;
int d[maxn],vis[maxn],a[maxn];
vector<pair<int,int> >e[maxn];
void init(){
forn(i,maxn){
e[i].clear();
d[i] = inf;
vis[i] = 0;
}
}
void dij(int s){
forn(i,maxn) d[i] = inf,vis[i] = 0;
priority_queue<pair<int,int> >q;
d[s] = 0;
q.push({0,s});
while(!q.empty()){
auto now = q.top();q.pop();
int u = now.second,w = now.first;
if(vis[u]) continue;
vis[u] = 1;
for(auto x:e[u])if(!vis[x.first]){
int v = x.first,y = x.second;
if(d[v]>y-w){
d[v] = y-w;
q.push({w-y,v});
}
}
}
}
int main(){
IO;
int t;cin>>t;
while(t--){
init();
int n,m,s,k,c;cin>>n>>m>>s>>k>>c;
forn(i,k) cin>>a[i];
forn(i,m){
int x,y,z;cin>>x>>y>>z;
e[x].push_back({y,z});
e[y].push_back({x,z});
}
int ans = 0,ans2 = 0;
dij(s);
for1(i,n) ans = max(ans,d[i]);
forn(i,k) e[0].push_back({a[i],0});
dij(0);
for1(i,n) ans2 = max(ans2,d[i]);
if(ans<=ans2*c) cout<<ans<<'\n';
else cout<<ans2<<'\n';
}
return 0;
}
瀋陽B題 並查集建圖
這題很難讀懂,讀懂之後我們縮點建圖,怪物點作爲隔絕的牆,其他聯通都用並查集連起來。然後在新圖跑一邊即可。
代碼:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int maxn = 1e5+5;
int n,m,k;
int par[maxn],rankk[maxn];
bool vis[maxn];
vector<pair<int,int> >e[maxn];
map<pair<int,int>,int>mp;
void init(){
forn(i,n+1) {
par[i] = i;
rankk[i] = 1;
vis[i] = 0;
e[i].clear();
}
mp.clear();
}
int find(int x){
return par[x] == x?x:par[x] = find(par[x]);
}
void unit(int x,int y){
x = find(x),y = find(y);
if(x==y) return;
if(rankk[x]<rankk[y])swap(x,y);
par[y] = x;
rankk[x] += rankk[y];
}
int main(){
IO;cout.precision(10);cout<<fixed;
int t;cin>>t;
while(t--){
cin>>n>>m>>k;
init();
forn(i,m){
int x,y;cin>>x>>y;
if(x>y)swap(x,y);
mp[{x,y}]++;
}
forn(i,k) {
int x;cin>>x;
vis[x] = 1;
}
for(auto &x:mp){
auto &z = x.first;
if(vis[z.first]||vis[z.second]) continue;
unit(z.first,z.second);
}
for(auto &x:mp){
int y = x.first.first,z = x.first.second;
y = find(y),z = find(z);
if(z!=y){
e[y].push_back({z,x.second});
e[z].push_back({y,x.second});
}
}
double ans = 0;
int root = find(1);
for(auto &x:e[root]){
ll sum = 0;
double res = 0;
int u = x.first;
for(auto &v:e[u]) sum+=v.second;
for(auto &v:e[u]){
double tem = (1.0*rankk[v.first]*v.second)/sum;
if(v.first!=root&&!vis[v.first]) res+=tem;
}
ans = max(res,ans);
}
ans+=rankk[root];
cout<<ans<<'\n';
}
return 0;
}
19上海 G Substring
Hash 好題 已單獨寫了一篇
#include <bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int maxn = 2e4+5;
const int maxm = 1e5+5;
const int seed = 131;
unordered_map<ull,int>mp[26][26];
unordered_map<ull,bool>vis[26][26];
string z,s;
int ans[maxn],n;
ull p[30];
struct Q{
int id,len,l,r;
ull has;
}q[maxn];
bool cmp(Q a,Q b){
return a.len<b.len;
}
void getans(int x){
if(x>n) return;
int l = 0,r = 0;
ull res = 0;
while(r<x) res+=p[s[r]-'a'],r++;
if(vis[s[l]-'a'][s[r-1]-'a'].count(res)) mp[s[l]-'a'][s[r-1]-'a'][res]++;
while(r<n){
res-=p[s[l]-'a'],l++,res+=p[s[r]-'a'];
if(vis[s[l]-'a'][s[r]-'a'].count(res)) mp[s[l]-'a'][s[r]-'a'][res]++;
r++;
}
}
void init(){
forn(i,26) forn(j,26) mp[i][j].clear(),vis[i][j].clear();
}
int main(){
IO;
p[0] = 1;
for1(i,26) p[i] = p[i-1]*seed;
int t;cin>>t;
while(t--){
cin>>s;
init();
n = s.size();
int m;cin>>m;
for1(i,m) {
cin>>z;
int len = z.size();
q[i].len = len;
q[i].id = i;
q[i].l = z[0]-'a';
q[i].r = z[len-1]-'a';
q[i].has = 0;
forn(j,len) {
q[i].has+=p[z[j]-'a'];
//cerr<<z[j]-'a'<<' '<<p[z[j]-'a']<<"@!#"<<'\n';
}
//cerr<<len<<' '<<p[0]<<' '<<q[i].has<<'\n';
vis[q[i].l][q[i].r][q[i].has] = true;
}
sort(q+1,q+m+1,cmp);
for1(i,m){
// cerr<<q[i].l<<' '<<q[i].r<<' '<<q[i].has<<'\n';
if(q[i].len!=q[i-1].len) getans(q[i].len);
ans[q[i].id] = mp[q[i].l][q[i].r][q[i].has];
}
for1(i,m) cout<<ans[i]<<'\n';
}
return 0;
}