1005
题意:输入n,m;接下来n个数,让我们从第一个数出发,一直循环走下去,每次加上这个位置的数。然后是m个询问,每次输入一个整数,问是否能走出这个数字,如果可以输出最小步数,否则输出-1。
显然我们第一步要去求n个数的前缀和以及走完一圈的增值res(最后一个前缀和)
ps:如果询问是0,直接输出0即可(要特判)。
显然如果res==0的话很明显直接记每个前缀和的位置即可。
然后再看res不为0的情况:
我们发现如果能出现这个数字
s
s
s的话,
∃
i
\exists i
∃i 满足
s
u
m
[
i
]
+
K
∗
r
e
s
=
s
sum[i]+K*res=s
sum[i]+K∗res=s而且
K
≥
0
K \geq 0
K≥0,所以
s
≡
s
u
m
[
i
]
(
m
o
d
r
e
s
)
s \equiv sum[i](\mod res)
s≡sum[i](modres)
那我们就预处理每个
s
u
m
[
i
]
sum[i]
sum[i]模
r
e
s
res
res的值
x
x
x。如果这个模数没出现过就新开一个vector,但是数据太大,要用map转换一下,虽然模数很大,但是n很小,所以vector最多也就开1e5个,可以开下。
然后对每个vector排序(这里比赛的时候傻逼了,只排了值升序,但是其实位置大的应该比位置小的更差,不懂这个为啥没看出来 )
最后每个询问x,就算出相应的模数s和除数y,在相应模数的vector里,找到刚好
≤
y
\leq y
≤y的一个值
z
z
z,如果没有也是-1,不然答案就是
n
∗
(
y
−
z
)
+
i
d
x
n*(y-z)+idx
n∗(y−z)+idx
一个注意点(比赛的时候也没看出来哭哭 ):就是负数算除法,因为在取模意义下,
[
−
n
,
−
1
]
[-n,-1]
[−n,−1]这部分除数应该是
−
1
-1
−1,但是直接算除法的话除了(-n)都是0,这里也要修改。
另外上面是对于 r e s > 0 res > 0 res>0的情况,如果 r e s < 0 res<0 res<0,就把每个 s u m [ i ] sum[i] sum[i]取反,每个询问也取反,就是 r e s > 0 res>0 res>0的情况了
#include<bits/stdc++.h>
#define pll pair<long long,long long>
#define line pair<double,double>
#define mp make_pair
#define pb push_back
#define ll long long
#define INF 123456789123456789
#define inf 0x3f3f3f3f
#define pi acos(-1)
#define db(x) cout<<x<<" "
#define dl(x) cout<<x<<endl
#define ls now<<1
#define rs now<<1|1
using namespace std;
const int mod = 998244353;
const int MAXN = 2e5 + 10;
const int N = 1e5 + 10;
const double eps = 1e-6;
int n, m;
map<ll, ll>ma;
struct node {
ll val, idx;
};
vector<node>q[N];
bool cmp(node a, node b)
{
if (a.val == b.val)return a.idx > b.idx;
return a.val < b.val;
}
ll tot;
ll s[N];
bool check(int res, ll z, ll x)
{
if (q[z][res].val <= x)return true;
return false;
}
ll query(ll x, ll z)
{
int l = 0, r = q[z].size() - 1;
int d = -1;
while (l <= r)
{
int mid = (l + r) >> 1;
if (check(mid, z, x))
{
d = mid;
l = mid + 1;
}
else r = mid - 1;
}
//cout<<"d="<<d<<" x="<<x<<" z="<<z<<endl;
//cout<<"val="<<q[z][d].val<<" id="<<q[z][d].idx<<endl;
if (d == -1)return -1;
else return (x - q[z][d].val) * n + q[z][d].idx;
}
void work()
{
ma.clear();
tot = 0;
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> s[i];
s[i] += s[i - 1];
}
ll res = s[n];
int tag = 0;
if (res < 0)
{
tag = 1;
res = -res;
for (int i = 1; i <= n; i++)s[i] = -s[i];
}
if (res == 0)
{
for (int i = 1; i <= n; i++)
{
if (!ma[s[i]])ma[s[i]] = i;
}
for (int i = 1; i <= m; i++)
{
ll x; cin >> x;
if (x == 0)
{
cout << 0 << endl;
continue;
}
if (ma[x])cout << ma[x] << endl;
else cout << -1 << endl;
}
}
else
{
for (int i = 1; i <= n; i++)
{
ll x = s[i] / res, ss = (s[i] % res + res) % res;
if (s[i] < 0)
{
if ((-s[i]) % res != 0)x--;
}
if (!ma[ss])
{
ma[ss] = ++tot;
q[tot].clear();
q[tot].pb({ x,i });
}
else
{
q[ma[ss]].pb({ x,i });
}
}
for (int i = 1; i <= tot; i++)
{
sort(q[i].begin(), q[i].end(), cmp);
//for(auto s:q[i])cout<<i<<" "<<s.val<<" "<<s.idx<<endl;
}
for (int i = 1; i <= m; i++)
{
ll x;
cin >> x;
if (tag)x = -x;
if (x == 0)
{
cout << 0 << endl;
continue;
}
ll y = x / res, ss = (x % res + res) % res;
//cout<<"ss="<<ss<<endl;
if (x < 0)
{
if ((-x) % res != 0)y--;
}
if (!ma[ss])cout << -1 << endl;
else cout << query(y, ma[ss]) << endl;
}
}
}
int main() {
std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int _ = 1;
cin >> _;
while (_--)work();
return 0;
}
1011
题意:给定一个n,接下来n-1行,输入u,v表示u,v之间有一条边。然后n个数表示 i 节点的大小。然后定义如果一条简单路径 ( u − > v ) (u->v) (u−>v) v v v的大小是这条路径上最大的,那么u就可以跳到到v。输出n行,表示从第 i 个节点出发,至多能走几个点。
思路:我们就直接按大小排序,从最小的值开始,然后去遍历这个点的所有邻边,如果邻接点出现过(较小值),就把当前点作为邻接点的父亲,新建一棵树。然后每个节点的答案就是当前节点的深度(根结点为1)
我是直接带权并查集记st直接算,或者直接新建一棵树算深度都行。
#include<bits/stdc++.h>
#define pll pair<int,int>
#define line pair<double,double>
#define mp make_pair
#define pb push_back
#define ll long long
#define INF 123456789123456789
#define inf 0x3f3f3f3f
#define pi acos(-1)
#define db(x) cout<<x<<" "
#define dl(x) cout<<x<<endl
#define ls now<<1
#define rs now<<1|1
using namespace std;
const int mod = 998244353;
const int MAXN = 2e5 + 10;
const int N = 1e5 + 10;
const double eps =1e-6;
int n, m;
struct node{
int t,nex;
}e[MAXN];
int head[N],cnt;
void add(int a,int b)
{
e[++cnt].nex=head[a];e[cnt].t=b;head[a]=cnt;
}
int st[N],num[N],fa[N];
int find(int x)
{
if(fa[x]==x)return fa[x];
int fx=find(fa[x]);
st[x]+=st[fa[x]];
return fa[x]=fx;
}
pll f[N];
int vs[N];
bool cmp(pll a,pll b)
{
return a.first<b.first;
}
void dfs(int u)
{
int b=find(u);
ll res=0;
for(int i=head[u];i;i=e[i].nex)
{
int v=e[i].t;
if(!vs[v])continue;
int a=find(v);
fa[a]=b;
st[a]+=num[b];
res+=num[a];
num[a]=0;
}
num[b]+=res;
}
void work()
{
cin>>n;
cnt=0;
for(int i=1;i<=n;i++)
{
head[i]=0,fa[i]=i,num[i]=1,st[i]=0,vs[i]=0;
}
for(int i=1;i<n;i++)
{
int a,b;cin>>a>>b;
add(a,b);add(b,a);
}
for(int i=1;i<=n;i++)
{
cin>>f[i].first;
f[i].second=i;
}
sort(f+1,f+1+n,cmp);
for(int i=1;i<=n;i++)
{
dfs(f[i].second);
vs[f[i].second]=1;
}
for(int i=1;i<=n;i++)
{
find(i);
}
for(int i=1;i<=n;i++)
{
cout<<st[i]+1<<endl;
}
}
int main() {
std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int _ = 1;
cin >> _;
while (_--)work();
return 0;
}