20180909徐州網絡賽題解
目錄
- 20180909徐州網絡賽題解
- A. Hard to prepare
- MEANING
- SOLUTION
- CODE
- B. BE, GE or NE
- MEANING
- SOLUTION
- CODE
- F. Features Track
- CODE
- G. Trace
- MENING
- SOLUTION
- CODE
- H. Ryuji doesn‘t want to study
- MEANING
- CODE
- I. Characters with Hash
- CODE
- J. Maze Designer
- MEANING
- SOLUTION
- CODE
- A. Hard to prepare
20180909徐州網絡賽題解
A. Hard to prepare
MEANING
n個點的環,每個點在[0,$2^{k-1}$] 之間選一個值。要求相鄰兩點的權值的二進制至少有一位相同。問方案數
SOLUTION
斷環為鏈,類似染色問題遞歸推導,考慮到爆棧,可能要把遞歸改成遞推
CODE
隊友代碼
#include <bits/stdc++.h> using namespace std; const long long mod=1e9+7; long long qpow(long long a,long long b) { long long res=1; while(b) { if(b%2) res = res*a%mod; a = a*a%mod; b = b/2; } return res; } long long n,k; long long dp[1000005]; int main() { int t; scanf("%d",&t); while(t--) { scanf("%lld %lld",&n,&k); long long x; x = qpow(2,k); dp[1] = x; dp[2] = x*(x-1)%mod; for(int i=3;i<=n;i++) { dp[i] = ( dp[i-2]*(x-1)%mod + ( x*qpow((x-1+mod)%mod,i-2)%mod-dp[i-2] +mod )%mod*(x-2)%mod )%mod; } printf("%lld\n",dp[n]); } return 0; }
B. BE, GE or NE
MEANING
兩個人玩一個galgame,一個人想GoodEnding,另一個想BadEnding。兩人輪流選擇劇情分支,劇情分支有三種,一種會使好感度增加,第二種會使好感度減少,第三種會使好感度取反。兩人都很聰明,問遊戲最後結局(只取決於好感度)如何。
SOLUTION
由於範圍很小,考慮dp
CODE
隊友代碼
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<ll,ll> pll; const ll maxn = 1000005; const ll mod = 1000000007; ll n,m,k,l; ll dp[1005][205]; ll a[1005][5]; int main() { scanf("%lld%lld%lld%lld",&n,&m,&k,&l); k+=100; l+=100; m+=100; for (int i=1; i<=n; i++) { for (int j=1; j<=3; j++) { scanf("%lld",&a[i][j]); } } for (int j=0; j<=200; j++) dp[n+1][j]=j; for (int i=n; i>=1; i--) { for (int j=200; j>=0; j--) { if (i%2) { dp[i][j]= 0; if (a[i][1]) dp[i][j]= max(dp[i][j],dp[i+1][min(j+a[i][1],200ll)]); if (a[i][2]) dp[i][j]= max(dp[i][j],dp[i+1][max(j-a[i][2],0ll)]); if (a[i][3]) dp[i][j]= max(dp[i][j],dp[i+1][200-j]); } else { dp[i][j]= 200; if (a[i][1]) dp[i][j]= min(dp[i][j],dp[i+1][min(j+a[i][1],200ll)]); if (a[i][2]) dp[i][j]= min(dp[i][j],dp[i+1][max(j-a[i][2],0ll)]); if (a[i][3]) dp[i][j]= min(dp[i][j],dp[i+1][200-j]); } } } ll ans = dp[1][m]; if (ans>=k) printf("Good Ending\n"); else if (ans<=l) printf("Bad Ending\n"); else printf("Normal Ending\n"); return 0; }
F. Features Track
CODE
隊友代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
const ll maxn = 1000005;
const ll mod = 1000000007;
map<pll,ll> mp[2];
int main() {
ll t;
scanf("%lld",&t);
while(t--) {
ll n;
scanf("%lld",&n);
ll cur = 0;
mp[0].clear();
mp[1].clear();
ll ans = 0;
for (ll i=1; i<=n; i++) {
ll pre = cur;
cur = 1-cur;
mp[cur].clear();
ll k ;
scanf("%lld",&k);
set<pll> ss;
for (ll j=1; j<=k; j++) {
ll x,y;
scanf("%lld%lld",&x,&y);
pll cat = pll(x,y);
ll val = 1 + mp[pre][cat];
ans = max(ans,val);
mp[cur][cat]=val;
}
}
printf("%lld\n",ans);
}
return 0;
}
G. Trace
MENING
在平面坐標系xOy的第一象限中,給你一個點,分別向xy軸作垂線可以和坐標軸圍成一個矩形。現在依次給出n個點,後來的矩形會覆蓋前面的,保證一個矩形不會被完全覆蓋,問圖中紅線長度。
SOLUTION
我們可以倒序向圖中加入點。
每當一個點加入時,分別向xy軸作垂線直到碰到紅線時停下,答案就會增加所畫線段的長度。
可以分別對x軸y軸建線段樹,區間修改,單點查詢。註意需要離散化。
CODE
#define FILE_IN() freopen("C:\\Users\\dmt\\Desktop\\in.txt","r",stdin);
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 50005;
struct sgt {
struct SegmentTree {
int l,r;
ll sum,add;
#define l(x) tree[x].l
#define r(x) tree[x].r
#define sum(x) tree[x].sum
#define add(x) tree[x].add
} tree[MAXN<<2];
int a[MAXN],n;
void build(int p,int l,int r) {
l(p) = l,r(p) = r;
if(l==r) {
sum(p) = a[l];
return;
}
int mid = (l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
sum(p) = sum(p*2) + sum(p*2+1);
}
void spread(int p) {
if(add(p)) {
sum(p*2)+=add(p)*(r(p*2)-l(p*2)+1);
sum(p*2+1)+=add(p)*(r(p*2+1)-l(p*2+1)+1);
add(p*2)+=add(p);
add(p*2+1) += add(p);
add(p) = 0;
}
}
void change(int p,int l,int r,int d) {
if(l<=l(p)&&r>=r(p)) {
sum(p)+=(ll)d*(r(p)-l(p)+1);
add(p)+=d;
return;
}
spread(p);
int mid = (l(p)+r(p))/2;
if(l<=mid)change(p*2,l,r,d);
if(r>mid) change(p*2+1,l,r,d);
sum(p) = sum(p*2)+sum(p*2+1);
}
ll ask(int p,int l,int r) {
if(l<=l(p)&&r>=r(p))return sum(p);
spread(p);
int mid = (l(p)+r(p))/2;
ll val = 0;
if(l<=mid)val+=ask(p*2,l,r);
if(r>mid)val+=ask(p*2+1,l,r);
return val;
}
} axis_x,axis_y;
struct data{
int x,y,ind;
int lx,ly;
}point[MAXN];
int lisan_x[MAXN],lisan_y[MAXN];
bool cmpx(data a,data b){
if(a.x!=b.x)return a.x<b.x;
return a.ind<b.ind;
}
bool cmpy(data a,data b){
if(a.y!=b.y)return a.y<b.y;
return a.ind<b.ind;
}
bool cmp(data a,data b){
return a.ind<b.ind;
}
int main() {
// FILE_IN();
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&point[i].x,&point[i].y);
point[i].ind = i;
}
//離散化
sort(point+1,point+n+1,cmpx);
for(int i=1;i<=n;i++){
lisan_x[i] = point[i].ind;
point[i].lx = i;
}
sort(point+1,point+n+1,cmpy);
for(int i=1;i<=n;i++){
lisan_y[i] = point[i].ind;
point[i].ly = i;
}
sort(point+1,point+n+1,cmp);
for(int i=1;i<=n;i++){
axis_x.a[i] = axis_y.a[i] = 0;
}
//建線段樹
axis_x.build(1,1,n);
axis_y.build(1,1,n);
ll ans = 0;
for(int i = n;i>=1;i--){
ll lx = point[i].lx;
ll ly = point[i].ly;
ll x = point[i].x;
ll y = point[i].y;
ll downy = axis_x.ask(1,lx,lx);
ll downx = axis_y.ask(1,ly,ly);
ans += x-point[lisan_x[downx]].x;
ans += y-point[lisan_y[downy]].y;
axis_x.change(1,downx,lx,ly-downy);
axis_y.change(1,downy,ly,lx-downx);
}
cout<<ans<<endl;
return 0;
}
H. Ryuji doesn‘t want to study
MEANING
給一個長度為n的數組a[n],q次詢問,每次詢問給出一個長度為L的區間[l,r],回答
a[l]×L+a[l+1]×(L?1)+?+a[r?1]×2+a[r]
CODE
隊友代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
const ll maxn = 1000005;
const ll mod = 1000000007;
ll n,q;
struct ST {
ll c[maxn];
ll lowbit(ll x) {
return -x&x;
}
void update(ll x,ll v) {
while(x<=n) {
c[x]+=v;
x+=lowbit(x);
}
}
ll query(ll x) {
ll ret = 0;
while(x>0) {
ret+=c[x];
x-=lowbit(x);
}
return ret;
}
ll query(ll l,ll r) {
return query(r)-query(l-1);
}
} s1,s2;
ll a[maxn];
int main() {
scanf("%lld%lld",&n,&q);
for (int i=1; i<=n; i++) {
scanf("%lld",&a[i]);
s1.update(i,a[i]*(n-i+1));
s2.update(i,a[i]);
}
for (ll qq =1; qq<=q; qq++) {
ll op;
scanf("%lld",&op);
if (op==1) {
ll l,r;
scanf("%lld%lld",&l,&r);
ll ans = s1.query(l,r) - s2.query(l,r)*(n-r);
printf("%lld\n",ans);
} else {
ll x,y;
scanf("%lld%lld",&x,&y);
s2.update(x,y-a[x]);
s1.update(x,(y-a[x])*(n-x+1));
a[x]=y;
}
}
return 0;
}
I. Characters with Hash
簽到題
CODE
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
const ll maxn = 1000005;
const ll mod = 1000000007;
char str[maxn];
int cnt = 0;
int main() {
ios::sync_with_stdio(false);
cin.tie();
int t;
cin>>t;
while(t--) {
int n;
char ch;
cin>>n;
cin>>ch;
cin>>str;
cnt = 0;
for (int i=0; i<n; i++) {
int tmp = abs(ch-str[i]);
if (tmp==0)
cnt+=2;
else if (tmp<10) {
cnt++;
break;
} else
break;
}
int ans = n*2-cnt;
if (ans==0)
ans=1;
cout<<ans<<endl;
}
return 0;
}
J. Maze Designer
MEANING
給一個n*m的網格圖,給出每個格子與它相鄰格子之間建堵墻的花費,要你找到一種建墻方案,使得在滿足圖中任意兩個格子只有一條路徑的前提下,總花費最小。然後就該方案給出q次詢問,每次詢問給定的兩點之間的距離。
SOLUTION
題目要求圖中任意兩個格子只有一條路徑,實際上就是一棵樹。既然建墻(拆邊)的總花費要最小,那麽建邊的總花費就是最大。所以跑一邊Kruskal,求出最大生成樹,時間復雜度O(nmlog(nm))。在樹上詢問兩點之間的距離可以通過求出最近公共祖先,兩點之間的距離就是dist(x,y) = deep(x)+deep(y)-2*deep(LCA(x,y)),時間復雜度O(qlog(nm))。
CODE
#define FILE_IN() freopen("C:\\Users\\dmt\\Desktop\\in.txt","r",stdin);
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 250005;
const int MAXE = 500005;
int n,m,t;
struct rec{
int x,y,z;
}mapp[500010];
int cnt;
bool cmp(rec a,rec b){
return a.z>b.z;
}
struct edge{
int u,v,w,nex;
}ed[MAXE];
int head[MAXN],tot;
void addedge(int u,int v,int w){
tot++;
ed[tot].u = u;
ed[tot].v = v;
ed[tot].w = w;
ed[tot].nex = head[u];
head[u] = tot;
}
int fa[MAXN];
int DjsGet(int x){
if(x==fa[x])return x;
return fa[x] = DjsGet(fa[x]);
}
int deep[MAXN],anc[MAXN][20];
queue<int> q;
void bfs() {
q.push(1);
deep[1] = 1;
while(q.size()) {
int x = q.front();
q.pop();
for(int i=head[x]; i; i=ed[i].nex) {
int y = ed[i].v;
if(deep[y])continue;
deep[y] = deep[x]+1;
anc[y][0] = x;
for(int j=1;j<t;j++){
anc[y][j] = anc[anc[y][j-1]][j-1];
}
q.push(y);
}
}
}
int lca(int x,int y) {
if(deep[x]<deep[y])swap(x,y);
for(int i=t-1; i>=0; i--) //to same deep;
if(deep[y]<=deep[anc[x][i]])
x = anc[x][i];
if(x==y)return x;
for(int i=t-1; i>=0; i--)
if(anc[x][i]!=anc[y][i]) {
x = anc[x][i];
y = anc[y][i];
}
return anc[x][0];
}
int main() {
// FILE_IN();
scanf("%d%d",&n,&m);
t = (int)log(n*m)/log(2)+1;
getchar();
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
int u = i*m+j+1;
char D,R;
D = getchar();
int w;
scanf("%d",&w);
getchar();
if(D=='D'){
int v = (i+1)*m+j+1;;
mapp[++cnt] = {u,v,w};
}
R = getchar();
scanf("%d",&w);
getchar();
if(R=='R'){
int v = i*m+j+2;
mapp[++cnt] = {u,v,w};
}
}
}
sort(mapp+1,mapp+cnt+1,cmp);
for(int i = 1;i<=n*m;i++)fa[i] = i;
for(int i=1;i<=cnt;i++){
int x = DjsGet(mapp[i].x);
int y = DjsGet(mapp[i].y);
if(x==y)continue;
fa[x] = y;
addedge(mapp[i].x,mapp[i].y,mapp[i].z);
addedge(mapp[i].y,mapp[i].x,mapp[i].z);
}
bfs();
int q;
scanf("%d",&q);
while(q--){
int x_1,y_1,x_2,y_2;
scanf("%d%d%d%d",&x_1,&y_1,&x_2,&y_2);
int u = (x_1-1)*m+y_1;
int v = (x_2-1)*m+y_2;
int la = lca(u,v);
printf("%d\n",deep[u]+deep[v]-2*deep[la]);
}
return 0;
}
20180909徐州網絡賽題解