按自己做题顺序和题目难易来编写此题解
C
本题是签到题,看了应该都有思路。
思路:我的思路比较简单,遍历一下然后,并且不会有前后相反方向,所以记录上一个方向pre,到下个的那个方向讨论一下另外两个方向,在改一下pre就可以了,代码如下:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define vi vector<int>
#define vvi vector<vi>
#define pb push_back
#define mp make_pair
#define endl '\n'
#define fo(i,l,r) for(int i=(l);i<=(r);++i)
const int N = 1e5+10;
const int mod = 1e9+7;
const int INF = 1e18;
void solve()
{
int n, m, k;
cin >> n;
queue<pair<char, int>> q;
char s;
int x;
for (int i = 0; i < n; ++i){
cin >> s >> x;
q.push({s, x});
}
int falg = 0;
cout << 2*n-1 << ' ';
char pre='#';
while (!q.empty()){
pair<char, int> p = q.front();
if (pre == '#'){
cout << p.first << endl;
pre = p.first;
cout << 'Z' << ' ' << p.second << endl;
q.pop();
continue;
}
if (pre=='S'){
if (p.first=='E') cout << 'L' << endl, pre = 'E';
else cout << 'R' << endl, pre = 'W';
}
else if (pre=='N'){
if (p.first == 'E') cout << 'R' << endl, pre = 'E';
else cout << 'L' << endl, pre = 'W';
}
else if (pre=='E'){
if (p.first == 'N') cout << 'L' << endl, pre = 'N';
else cout << 'R' << endl, pre = 'S';
}
else if (pre=='W'){
if (p.first == 'S') cout << 'L' << endl, pre = 'S';
else cout << 'R' << endl, pre = 'N';
}
cout << 'Z' << ' ' << p.second << endl;
q.pop();
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
M
思路:题意很简单,但纯照题写肯定会超时,所以不行,接下来我们就得优化。打表或者自己写一个简单样例会发现规律,和它的因数有关,加数方式如下:
f(4) 因数: 1 2 4
f(4) : 4 2 2 1
f(8) 因数: 1 2 4 8
f(8) : 8 4 4 2 2 2 2 1
加数归纳为:因数间隙*(n/该因数)
代码如下:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define vi vector<int>
#define pb push_back
#define endl '\n'
#define fo(i, l, r) for (int i = (l); i <= (r); ++i)
const int N = 1e5 + 10;
const int mod = 1e9 + 7;
const int INF = 1e18;
void solve()
{
int n, m, k;
cin >> n;
auto geta = [&](int num) -> vi
{
vi fac;
for (int i = 1; i * i <= num; ++i)
{
if (num % i == 0)
{
fac.pb(i);
if (i != num / i)
{
fac.pb(num / i);
}
}
}
sort(fac.begin(), fac.end());
return fac;
};
vi a = geta(n);
int pre = 1;
int res = 0;
for (auto x : a){
res += (x - pre) * (n / pre);
pre = x;
}
cout << res + 1 << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
G
思路:跑一个bfs,记录要输出的结果就行了
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define vi vector<int>
#define vvi vector<vi>
#define pb push_back
#define mp make_pair
#define endl '\n'
#define fo(i,l,r) for(int i=(l);i<=(r);++i)
const int mod = 1e9+7;
const int INF = 1e18;
const int N=2e5+5;
int n,m,k,x,y;
bool b[N],vis[N];
vector<int> e[N];
void adde(int x,int y){
e[x].push_back(y);
}
signed main(){
cin>>n>>m>>k;
for(int i=1;i<=k;++i)cin>>x,b[x]=1;
for(int i=1;i<=m;++i)cin>>x>>y,adde(x,y),adde(y,x);
queue<int> q;
for(int i=1;i<=n;++i)if(!b[i]){q.push(i),vis[i]=1;break;}
vector<vector<int>> ans;
while(!q.empty()){
int u=q.front();
q.pop();
if(b[u])continue;
vector<int> c;
c.push_back(u);
for(int v:e[u])if(!vis[v])c.push_back(v),q.push(v),vis[v]=1;
if(c.size()>1)ans.push_back(c);
}
int cnt=0;
for(int i=1;i<=n;++i)if(!vis[i])++cnt;
if(cnt){cout<<"No\n";return 0;}
cout<<"Yes\n";
cout<<ans.size()<<'\n';
for(auto c:ans){
cout<<c[0]<<' '<<c.size()-1<<' ';
for(int i=1;i<c.size();++i)cout<<c[i]<<' ';
cout<<'\n';
}
}
K
思路:保证每个都有最小的,再遍历每个算删除该中算最大,应该从比它大的那里加,又得保证不超出它们得最大,此处可以算个后缀和,再用二分来计算结果,二分之后要判断是否到打了该数,再讨论一下。代码如下:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define vi vector<int>
#define vvi vector<vi>
#define pb push_back
#define mp make_pair
#define endl '\n'
#define dbug() cout << '||||||debug|||||' << endl;
#define fo(i,l,r) for(int i=(l);i<=(r);++i)
const int N = 1e5+10;
const int mod = 1e9+7;
const int INF = 1e18;
struct node{
int w, l, r;
};
struct SB{
int ti, tal;
};
void solve()
{
int n, m, k;
int ma= 0;
cin >> n >> m;
vector<node> v(n+1);
for (int i = 1; i<=n; i++){
cin >> v[i].w >> v[i].l >> v[i].r;
}
vi pre(n+1), ti(n+1);
sort(v.begin()+1, v.end(), [](node a, node b){
return a.w < b.w;
});
for (int i = 1; i<=n; i++){
pre[i] = pre[i-1]+v[i].w*v[i].l;
ti[i] = ti[i-1]+v[i].l;
}
vector<SB> sb(n+2);
for (int i = n; i>=1; i--){
int tp = v[i].r-v[i].l;
sb[i].ti = sb[i+1].ti+tp;
sb[i].tal = sb[i+1].tal + tp*v[i].w;
}
for (int i = 1; i<=n; i++){
int val = pre[n]- v[i].w*v[i].l;
int tt = ti[n]-v[i].l;
tt = m-tt;
int l = i, r = n+1;
while (l+1 < r){
int mid = (l+r)/2;
if (sb[mid].ti <= tt){
r = mid;
}
else{
l = mid;
}
}
if(r!=i+1){
val += sb[r].tal;
int pp = tt-sb[r].ti;
val +=v[r-1].w*pp;
}else{
val += sb[r].tal;
int pp = tt-sb[r].ti;
val += v[i].w * pp;
}
ma = max(ma, val);
}
cout << ma << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
return 0;
}
J
思路:大型模拟题,按充电桩充的对应电池开始用电肯定是最好的,并且到一个充电桩就应该用下个对应的电池,此题用到了set<pair<int,int>>的数据结构会很容易,因为它能对键排序和去重
就不多介绍了,代码如下:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define vi vector<int>
#define vvi vector<vi>
#define pb push_back
#define mp make_pair
#define endl '\n'
#define fo(i,l,r) for(int i=(l);i<=(r);++i)
const int N = 2e5+10;
const int mod = 1e9+7;
const int INF = 1e18;
int a[N], now[N], pos[N], xi[N], fir[N], lst[N], nxt[N];
void solve()
{
int n, m, k;
cin >> n >> m;
fo(i,1,n) cin >> a[i], now[i] = a[i];
fo(i,1,m) cin >> pos[i] >> xi[i];
fo(i,1,n) fir[i] = m+1, lst[i] = 0;
fo(i,1,m){
if (fir[xi[i]] > m) fir[xi[i]] = i;
if (lst[xi[i]]) nxt[lst[xi[i]]] = i;
lst[xi[i]] = i;
}
for (int i = 1; i<=n; i++) if (lst[i]) nxt[lst[i]] = m+1;
set<pair<int, int>> s;
for (int i = 1; i<=n; i++) s.insert(pair<int, int>(fir[i], i));
int sum = 0;
for (int i = 1; i<=m; i++){
int r = pos[i]-pos[i-1];
while (!s.empty() && now[s.begin()->second] <= r){
int k = s.begin()->second;
sum += now[k];
r -= now[k];
now[k]=0;
s.erase(s.begin());
}
if (s.empty() && r > 0) {
cout << sum << endl;
return ;
}
now[s.begin()->second] -= r;
sum += r;
now[xi[i]] = a[xi[i]];
if (s.find(pair<int, int>(i, xi[i]))!= s.end()) s.erase(pair<int, int>(i, xi[i]));
s.insert(pair<int, int>(nxt[i], xi[i]));
}
for (int i = 1; i<=n; i++) sum += now[i];
cout << sum << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
L
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int long long
const int N=1e5+11;
const LL MOD=998244353;
int n;
vector<int> e[N];
LL dp[N][3];//dp[u][i]表示u节点子树内所有到u的边非空“半路径”的i次项的和
LL sz[N],ss[N];
LL ksm(LL a,LL x){//求逆元
LL ret=1;
a=(a%MOD+MOD)%MOD;
while(x){
if(x&1)ret=ret*a%MOD;
a=a*a%MOD;
x>>=1;
}
return ret;
}
void dfs_pre(int now,int fa){//求k
sz[now]=1;
ss[now]=0;
for(int to:e[now]){
if(to==fa)continue;
dfs_pre(to,now);
sz[now]+=sz[to];
ss[now]+=sz[to]*sz[to]%MOD;
}
ss[now]%=MOD;
}
void dfs(int now,int fa,LL &ans){
memset(dp[now],0,sizeof(dp[now]));
for(int to:e[now]){
if(to==fa)continue;
dfs(to,now,ans);
LL t[3];
t[0]=dp[to][0];
t[1]=(dp[to][1]+dp[to][0])%MOD;
t[2]=(dp[to][2]+2ll*dp[to][1]+dp[to][0])%MOD;//t[0...3]所有半路径的长度+1
for(int i=0;i<3;++i){//加入v到u的“半路径”
t[i]=(t[i]+sz[to]*sz[to]%MOD-ss[to])%MOD;
}
LL tmp=t[0]*dp[now][2]%MOD+dp[now][0]*t[2]%MOD+2ll*t[1]*dp[now][1]%MOD;
tmp+=((n-sz[to])*(n-sz[to])%MOD-ss[now]+sz[to]*sz[to]%MOD-(n-sz[now])*(n-sz[now])%MOD)%MOD*t[2];
ans+=tmp%MOD;
for(int i=0;i<3;++i){
dp[now][i]=(dp[now][i]+t[i])%MOD;
}
}
}
void work(){
cin>>n;
for(int i=1;i<=n;++i){
e[i].clear();
}
for(int i=0;i<n-1;++i){
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
LL ans=0;
dfs_pre(1,0);
dfs(1,0,ans);
ans=(ans%MOD+MOD)%MOD;
LL ii=ksm(1ll*n*(n-1)/2ll,MOD-2);
cout<<ans*ii%MOD*ii%MOD<<"\n";
}
signed main(){
int T;
cin>>T;
while(T--){
work();
}
return 0;
}