以下所有AC题解程序来自“仙客传奇”团队。
解题思路:先编写离线程序计算出最小的5个完美数,用那5个数编写解题程序。
计算最小完美数的离线程序:I00035 完美数(Perfect number)
暴力法是搞不定的。以下的暴力计算完美数程序,运行了一个多小时,只出四个数:
AC的C++语言程序如下:
#include <stdio.h>
int ans[] = {6, 28, 496, 8128, 33550336};
const int N = sizeof(ans) / sizeof(int);
int main()
{
for(int i = 0; i < N; i++)
printf("%d\n", ans[i]);
return 0;
}
最简洁的代码,AC的C语言程序如下:
#include <stdio.h>
int main(){puts("6\n28\n496\n8128\n33550336\n"); return 0;}
比赛官方题解代码(C语言):
#include <stdio.h>
int main(){
int x[5] = {1, 2, 4, 6, 12};
int i;
for(i = 0; i < 5; i++) {
printf("%d\n", (1 << x[i]) * ((1 << x[i] + 1) - 1));
}
return 0;
}
题解链接:【2019南昌邀请赛网络赛 B Greedy HOUHOU & BZOJ 2957 楼房重建】线段树+二分
C. Angry FFF Party
AC的Java语言程序:
import java.util.Scanner;
import java.math.BigInteger;
import java.util.ArrayList;
/**
* 解决问题的核心类,使用矩阵快速幂来计算斐波那契数列的某一项,
* 由于题目数列是F(F(x)),可以发现这个数列增长非常快,
* 因为数值很大,使用Java的BigInteger类存放。
* 对于<=10的部分,因为要求字典序最小解,因此需要特判。
* 对于>10的部分,可以发现分解方式唯一,直接倒着贪心减去打表内的数据就好了。
*/
public class Main {
// LIM表示打表的大小,根据输入数据的大小调整这个值来打不同范围的表
private static int LIM = 30;
// ZERO、ONE、TWO都是预定义的BigInteger类实例,用来表示数值0、1、2
private static final BigInteger ZERO = BigInteger.valueOf(0);
private static final BigInteger ONE = BigInteger.valueOf(1);
private static final BigInteger TWO = BigInteger.valueOf(2);
// 存放打好的表,table[i]将等于F(F(i))的函数值
private static BigInteger[] table;
/**
* 解决问题的主方法
*/
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
build(LIM);
int t;
t = in.nextInt();
for (int k = 0; k < t; k++) {
BigInteger W;
W = in.nextBigInteger();
ArrayList<Integer> ans = new ArrayList<Integer>();
for (int i = table.length - 1; i > 5; i--) {
if (W.compareTo(table[i]) >= 0) {
W = W.subtract(table[i]);
ans.add(i);
}
}
boolean flag = false;
if (W.compareTo(ZERO) != 0) {
if (W.compareTo(BigInteger.valueOf(10)) <= 0) {
if (W.compareTo(BigInteger.valueOf(1)) == 0)
System.out.print("1");
else if (W.compareTo(BigInteger.valueOf(2)) == 0)
System.out.print("1 2");
else if (W.compareTo(BigInteger.valueOf(3)) == 0)
System.out.print("1 2 3");
else if (W.compareTo(BigInteger.valueOf(4)) == 0)
System.out.print("1 2 4");
else if (W.compareTo(BigInteger.valueOf(5)) == 0)
System.out.print("1 2 3 4");
else if (W.compareTo(BigInteger.valueOf(6)) == 0)
System.out.print("1 5");
else if (W.compareTo(BigInteger.valueOf(7)) == 0)
System.out.print("1 2 5");
else if (W.compareTo(BigInteger.valueOf(8)) == 0)
System.out.print("1 2 3 5");
else if (W.compareTo(BigInteger.valueOf(9)) == 0)
System.out.print("1 2 4 5");
else
System.out.print("1 2 3 4 5");
flag = true;
} else {
System.out.println("-1");
continue;
}
}
for (int i = ans.size() - 1; i >= 0; i--) {
if (flag) System.out.print(" ");
flag = true;
System.out.print(ans.get(i));
}
System.out.println();
}
}
/**
* 用来进行打表操作的接口函数
* @param x 打表的大小
*/
private static void build(int x) {
table = new BigInteger[x + 1];
for (int i = 1; i <= x; i++)
table[i] = buildUtil(i);
}
/**
* 用来打表的实用函数,即计算某一项的函数
* @param x 所要计算的项数
* @return F(F(x))的值
*/
private static BigInteger buildUtil(int x) {
Matrix base = new Matrix();
base.d[0][0] = BigInteger.valueOf(1);
base.d[0][1] = BigInteger.valueOf(1);
base.d[1][0] = BigInteger.valueOf(1);
BigInteger tmp = fp(base, BigInteger.valueOf(x));
base = new Matrix();
base.d[0][0] = BigInteger.valueOf(1);
base.d[0][1] = BigInteger.valueOf(1);
base.d[1][0] = BigInteger.valueOf(1);
tmp = fp(base, tmp);
return tmp;
}
/**
* 矩阵快速幂,用来计算斐波那契数列的某一项
* @param b 底数
* @param p 指数
* @return 斐波那契数列的第p项,即F(p)
*/
private static BigInteger fp(Matrix b, BigInteger p) {
Matrix ret = new Matrix();
ret.d[0][0] = BigInteger.valueOf(1);
do {
if (p.remainder(TWO).compareTo(ONE) == 0) ret = b.mul(ret);
b = b.mul(b);
p = p.divide(TWO);
} while (p.compareTo(ZERO) > 0);
return ret.d[1][0];
}
}
/**
* 矩阵类,定义了矩阵的规模以及乘法运算
*/
class Matrix {
public BigInteger[][] d;
public Matrix() {
d = new BigInteger[2][2];
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
d[i][j] = BigInteger.valueOf(0);
}
public Matrix mul(Matrix m) {
Matrix ret = new Matrix();
for (int i = 0; i < 2; i++)
for (int k = 0; k < 2; k++)
// 左矩阵的d[i][k]位置上为0时不用计算,以此减少稀疏矩阵的计算量
if (d[i][k].compareTo(BigInteger.valueOf(0)) != 0)
for (int j = 0; j < 2; j++)
ret.d[i][j] = ret.d[i][j].add(d[i][k].multiply(m.d[k][j]));
return ret;
}
}
AC的C++语言程序:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<ctime>
#include<ctype.h>
#include<stdlib.h>
#include<bitset>
#include<algorithm>
#include<assert.h>
#include<numeric> //accumulate
#define endl "\n"
#define fi first
#define se second
#define FOR(i,s,t) for(int i=(s);i<=(t);++i)
#define mem(a,b) memset(a,b,sizeof(a))
#define rush() int MYTESENUM;scanf("%d",&MYTESENUM);while(MYTESENUM--)
#define debug(x) printf("%d\n",x)
using namespace std;
const int maxn=700+5;
const int c[]={6,2,5,5,4,5,6,3,7,6};
long long f[maxn][maxn][2];
int wi[100+5];
int n;
char expr[100+5];
inline long long power(int x)
{
return x==0?1:10*power(x-1);
}
bool vis[maxn][maxn][2];
inline long long DP(int i,int j,int k)
{
if(j<0)
return -1e16;
if(i>n&&j==0)
return 0;
if(i>n||j==0)
return -1e16;
if(expr[i-1]=='+'||expr[i-1]=='-')
{
return max(DP(i+1,j-2,0),DP(i+1,j-1,1));
}
else
{
if(vis[i][j][k])
return f[i][j][k];
vis[i][j][k]=1;
int it=0;
if(i==1||expr[i-2]=='+'||expr[i-2]=='-')
it=1;
long long& ans=f[i][j][k];
ans=-1e16;
for(;it<10;it++)
{
if(j>=c[it])
{
ans=max(ans,DP(i+1,j-c[it],k)+1ll*it*power(wi[i-1])*(k==0?1:-1));
}
}
return ans;
}
}
int main()
{
cin.tie(0);
cout.tie(0);
//ios_base::sync_with_stdio(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
rush()
{
scanf("%d",&n);
scanf(" %s",expr);
expr[n]='+';
int sum=0;
for(int i=0;i<=n;i++)
{
if(expr[i]=='+')
sum+=2;
else if(expr[i]=='-')
sum++;
else
{
sum+=c[expr[i]-'0'];
continue;
}
int j=i-1,k=0;
while(j>=0&&isdigit(expr[j]))
{
wi[j--]=k++;
}
}
sum-=2;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=sum;j++)
{
for(int k=0;k<2;k++)
{
vis[i][j][k]=0;
}
}
}
if(n==1&&expr[0]=='0')
printf("0\n");
else
printf("%lld\n",DP(1,sum,0));
}
}
AC的C++语言程序:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5;
const ll inf = 0x7f7f7f7f7f7f7f7f;
const int inf1 = 0x7f7f7f7f;
int num[10]= {6,2,5,5,4,5,6,3,7,6};
int digit[60],cnt;
ll dp[1000][60][2],Max[2][15][100];
void get() {
for(int i = 0; i <= 10; ++i)
for(int j = 0; j <= 80; ++j) {
Max[0][i][j] = inf1;
Max[1][i][j] = -inf1;
}
for(int i = 1; i <= 10; ++i)
for(int k = 1; k < 10; ++k) {
Max[1][i][6 * (i - 1) + num[k]] = max(Max[1][i][6 * (i - 1) + num[k]],k * (ll)pow(10,i - 1));
Max[0][i][6 * (i - 1) + num[k]] = min(Max[0][i][6 * (i - 1) + num[k]],k * (ll)pow(10,i - 1));
}
for(int i = 2; i <= 10; ++i)
for(int j = 2; j <= 80; ++j)
for(int k = 1; k < 10; ++k) {
if(j >= num[k]) {
if(Max[1][i - 1][j - num[k]] != -inf1) {
if(Max[1][i][j] < Max[1][i - 1][j - num[k]] + k * (ll)pow(10,i - 1))
Max[1][i][j] = Max[1][i - 1][j - num[k]] + k * (ll)pow(10,i - 1);
}
if(Max[0][i - 1][j - num[k]] != inf1) {
if(Max[0][i][j] > Max[0][i - 1][j - num[k]] + k * (ll)pow(10,i - 1))
Max[0][i][j] = Max[0][i - 1][j - num[k]] + k * (ll)pow(10,i - 1);
}
}
}
}
ll dfs(int res,int pos,bool flag) {
if(cnt == pos) {
if(res >= 80) return -inf1;
if(abs(Max[flag][digit[pos]][res]) == inf1) return -inf1;
else {
if(flag)
return Max[flag][digit[pos]][res];
else
return -Max[flag][digit[pos]][res];
}
}
if(dp[res][cnt - pos][flag] != -inf) return dp[res][cnt - pos][flag];
ll tmp = -inf;
for(int i = 1; i <= 80; ++i) {
if(i >= res) break;
if(abs(Max[flag][digit[pos]][i]) == inf1) continue;
if(flag) {
if(res >= i + 4) tmp = max(tmp,Max[flag][digit[pos]][i] + dfs(res - i - 2,pos + 1,true));
if(res >= i + 3) tmp = max(tmp,Max[flag][digit[pos]][i] + dfs(res - i - 1,pos + 1,false));
} else {
if(res >= i + 4) tmp = max(tmp,-Max[flag][digit[pos]][i] + dfs(res - i - 2,pos + 1,true));
if(res >= i + 3) tmp = max(tmp,-Max[flag][digit[pos]][i] + dfs(res - i - 1,pos + 1,false));
}
// cout<<res<<':'<<pos<<':'<<i<<':'<<Max[flag][digit[pos]][i]<<' '<<tmp<<endl;
}
dp[res][cnt - pos][flag] = tmp;
return tmp;
}
ll solve(string str) {
int total = 0;
cnt = 0;
memset(digit,0,sizeof(digit));
for(int i = 0; i < str.size(); ++i) {
if(isdigit(str[i])) {
total += num[str[i] - '0'];
++digit[cnt];
} else {
if(str[i] == '+')
total += 2;
else
total += 1;
++cnt;
}
}
return dfs(total,0,true);
}
int main() {
int t,n;
string str;
memset(Max[0],0x7f,sizeof(Max[0]));
get();
cin>>t;
while(t--) {
cin>>n>>str;
for(int i = 0; i < 1000; ++i)
for(int j = 0; j < 60; ++j)
for(int k = 0; k < 2; ++k)
dp[i][j][k] = -inf;
cout<<solve(str)<<endl;
}
return 0;
}
题解链接:
南昌邀请赛网络赛 G. tsy’s number(莫比乌斯反演+线性筛)
[计蒜客] tsy’s number 解题报告 (莫比乌斯反演+数论分块)
AC的C++语言程序:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<ctime>
#include<ctype.h>
#include<stdlib.h>
#include<bitset>
#include<algorithm>
#include<assert.h>
#include<numeric> //accumulate
#define endl "\n"
#define fi first
#define se second
#define FOR(i,s,t) for(int i=(s);i<=(t);++i)
#define mem(a,b) memset(a,b,sizeof(a))
#define rush() int MYTESENUM;scanf("%d",&MYTESENUM);while(MYTESENUM--)
using namespace std;
const long long mod=1e9+7;
long long solve(long long a,long long b)
{
long long ret=0;
if(b==0)
return 1;
if(b==1)
return a;
if(b&1)
{
ret=solve(a,b/2);
return (((ret*ret)%mod)*a)%mod;
}
else
{
ret=solve(a,b/2);
return (ret*ret)%mod;
}
}
int main()
{
cin.tie(0);
cout.tie(0);
//ios_base::sync_with_stdio(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
long long n;
cin>>n;
if(n==1)
cout<<1;
else
cout<<(4*solve(3,n-2))%mod;
}
每个位置都有3种情况,第一个位置不能是第二种, 最后一个位置不能是第一种,所以一共有2 * 3^(n-2) * 2种情况。
AC的C++语言程序:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
ll pow(ll a, ll p){
if (p == 0) return 1;
ll t = pow(a, p/2);
if (p &1) return t * t % mod * a % mod;
return t * t % mod;
}
int main(void) {
int n;
cin >> n;
if (n == 1) printf("1\n");
else printf("%lld", 4ll * pow(3ll, (ll)n - 2) % mod);
return 0;
}
AC的C++语言程序:
#include <iostream>
#include <set>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#define lo(i, n, m) for (int i = n; i < m; i++)
#define loe(i, n, m) for (int i = n; i <= m; i++)
#define rlo(i, n, m) for (int i = n - 1; i >= m; i--)
#define rloe(i, n, m) for (int i = n; i >= m; i--)
#define pb push_back
#define mk make_pair
#define clr(a, b) memset((a), (b), sizeof(a))
#define scd(x) scanf("%d", &x)
#define scs(x) scanf("%s", x)
#define sclf(x) scanf("%lf", &x)
#define scll(x) scanf("%lld", &x)
#define endl '\n'
using namespace std;
typedef long long LL;
template <class T>
inline void sw(T &a, T &b) {
T t = a;
a = b;
b = t;
}
template <class T>
inline T mx(T a, T b) {return b < a ? a : b;}
template <class T>
inline T mi(T a, T b) {return a < b ? a : b;}
template <class T>
inline T mabs(T x) {return x < 0 ? -x : x;}
inline char gc() {
char ch;
while ((ch = getchar()) == ' ' || ch == '\n' || ch == '\t');
return ch;
}
const int NIL = -1;
const LL MOD = 1e9 + 7;
inline int fp(int b, int p) {
int ret = 1;
do {
if (p & 1) ret = (int)(1ll * b * ret % MOD);
b = (int)(1ll * b * b % MOD);
} while (p >>= 1);
return ret;
}
// 使用快速模幂加速计算
int main(void) {
int n;
scd(n);
if (n == 1) printf("1\n");
else printf("%lld", 4ll * fp(3, n - 2) % MOD);
return 0;
}
AC的C++语言程序:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<ctime>
#include<ctype.h>
#include<stdlib.h>
#include<bitset>
#include<algorithm>
#include<assert.h>
#include<numeric> //accumulate
#define endl "\n"
#define fi first
#define se second
#define int long long
#define FOR(i,s,t) for(int i=(s);i<=(t);++i)
#define mem(a,b) memset(a,b,sizeof(a))
#define rush() int MYTESENUM;scanf("%d",&MYTESENUM);while(MYTESENUM--)
using namespace std;
const int maxn=500000+5;
int a[maxn];
struct node
{
int sum,mi,mx;
};
struct segmenttree
{
#define ls o<<1
#define rs o<<1|1
#define lss ls,l,mid
#define rss rs,mid+1,r
int sum[maxn<<2];
int val[maxn<<2];
int val1[maxn<<2];
inline void pushdown(int o)
{
sum[o]=sum[ls]+sum[rs];
val[o]=max(val[ls],sum[ls]+val[rs]);
val1[o]=min(val1[ls],sum[ls]+val1[rs]);
}
inline void build(int o,int l,int r)
{
if(l==r)
{
sum[o]=a[l];
val[o]=a[l];
val1[o]=a[l];
return ;
}
int mid=l+r>>1;
build(lss);
build(rss);
pushdown(o);
}
int ql,qr;
inline node query(int o,int l,int r)
{
if(l>=ql&&r<=qr)
{
return (node){sum[o],val1[o],val[o]};
}
int mid=l+r>>1;
node lt,rt;
if(mid>=ql)
lt=query(lss);
else
return query(rss);
if(qr>mid)
rt=query(rss);
else
return lt;
return (node){lt.sum+rt.sum,min(lt.mi,lt.sum+rt.mi),max(lt.mx,rt.mx+lt.sum)};
}
};
segmenttree T1,T2;
int l[maxn],r[maxn];
int n;
int32_t main()
{
cin.tie(0);
cout.tie(0);
//ios_base::sync_with_stdio(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
cin>>n;
for(int i=1; i<=n; i++)
{
cin>>a[i];
l[i]=r[i]=i;
}
for(int i=2; i<=n; i++)
{
int now=i;
while(now>1&&a[i]<=a[now-1])
now=l[now-1];
l[i]=now;
}
for(int i=n-1; i; i--)
{
int now=i;
while(now<n&&a[i]<=a[now+1])
now=r[now+1];
r[i]=now;
}
T1.build(1,1,n);
reverse(a+1,a+n+1);
T2.build(1,1,n);
reverse(a+1,a+n+1);
int ans=0;
for(int i=1;i<=n;i++)
{
if(a[i]==0)
continue;
if(a[i]>0)
{
int lg,rg;
if(l[i]==i)
lg=0;
else
{
T2.ql=n-(i-1)+1;
T2.qr=n-l[i]+1;
lg=T2.query(1,1,n).mx;
}
T1.ql=i,T1.qr=r[i];
rg=T1.query(1,1,n).mx;
ans=max(ans,(lg+rg)*a[i]);
}
else
{
int lg,rg;
if(l[i]==i)
lg=0;
else
{
T2.ql=n-(i-1)+1;
T2.qr=n-l[i]+1;
lg=T2.query(1,1,n).mi;
}
T1.ql=i,T1.qr=r[i];
rg=T1.query(1,1,n).mi;
ans=max(ans,(lg+rg)*a[i]);
}
}
cout<<ans;
}
维护6个值
L[i]—— i左面比a[i]小的第一个数的位置
R[i]—— i右面比a[i]小的第一个数的位置
lmax[i]—— 以i为右端点的区间最大值
lmin[i]—— 以i为右端点的区间最小值
rmax[i]—— 以i为左端点的区间最大值
rmin[i]—— 以i为左端点的区间最小值
如果 a[i] > 0 ans = max(ans, a[i] * (sum[min(R[i] - 1, rmax[i])] - sum[max(L[i] + 1, lmax[i])-1]));
a[i] < 0 ans = max(ans, a[i] * (sum[min(R[i] - 1, rmin[i])] - sum[max(L[i] + 1, lmin[i])-1]));
#include <bits/stdc++.h>
using namespace std;
const int maxn =5e5+10;
const int INF = 0x3f3f3f3f;
typedef long long ll;
int L[maxn], R[maxn], lmax[maxn], rmax[maxn], lmin[maxn], rmin[maxn], a[maxn];
ll sum[maxn];
stack<pair<int, int> > s;
int n;
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++){
scanf("%d", &a[i]);
sum[i] = sum[i - 1] + a[i];
}
s.push({1, a[1]});
R[n] = n+1;
a[n+1] = -INF;
a[0] = -INF;
for (int i = 2; i <= n+1; i++) {
while (!s.empty() && s.top().second > a[i]){
R[s.top().first] = i, s.pop();
}
s.push({i,a[i]});
}
s.push({n, a[n]});
for (int i = n-1; i >= 1; i--) {
while (!s.empty() && s.top().second > a[i]){
L[s.top().first] = i, s.pop();
}
s.push({i,a[i]});
}
lmax[1] = 1;
for (int i= 2; i <= n; i++){
if (sum[i - 1] - sum[lmax[i - 1] - 1] > 0) lmax[i] = lmax[i -1];
else lmax[i] = i;
}
lmin[1] = 1;
for (int i = 2; i <= n; i++){
if (sum[i - 1] - sum[lmin[i - 1] - 1 ]< 0) lmin[i] = lmin[i-1];
else lmin[i] = i;
}
rmax[n] = n;
for (int i =n -1; i>=1; i--) {
if (sum[rmax[i+1]] - sum[i] > 0) rmax[i] = rmax[i + 1];
else rmax[i] = i;
}
rmin[n] = n;
for (int i = n - 1; i>=1; i--){
if (sum[rmin[i+1]] - sum[i] < 0) rmin[i] = rmin[i + 1];
else rmin[i] = i;
}
ll ans = 0;
for (int i = 1; i <= n; i++){
if (a[i] > 0) ans = max(ans, (ll)a[i] * (sum[min(R[i] - 1, rmax[i])] - sum[max(L[i] + 1, lmax[i])-1]));
else if (a[i] < 0) ans = max(ans, (ll)a[i] * (sum[min(R[i] - 1, rmin[i])] - sum[max(L[i] + 1, lmin[i])-1]));
}
printf("%lld\n", ans);
return 0;
}
离线+线段树+树链剖分。参考链接:dfs序 与 树链剖分 例题 Distance on the tree
AC的C++语言程序:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+2;
const int maxm = 1e5+2;
struct Ques{
int l ,r, k, id;
}Q[maxm];
struct node{
int u, v, w;
}E[maxn];
int n , m, last;
bool cmp(const Ques A, const Ques B){
return A.k < B.k;
}
bool cmp2(const node A, const node B){
return A.w < B.w;
}
int Ans[maxn];
vector <int > edge[maxn];
int sz[maxn], son[maxn], pos[maxn], tot, dep[maxn], fa[maxn], top[maxn];
void dfs(int x, int u){
sz[x] = 1;son[x] = 0;
fa[x] = u;
for (int i = 0; i< edge[x].size(); i++){
if (edge[x][i] == fa[x]) continue;
dep[edge[x][i]] = dep[x] + 1;
dfs(edge[x][i], x);
sz[x] += sz[edge[x][i]];
if (sz[edge[x][i]] > sz[son[x]]) son[x] = edge[x][i];
}
}
void dfs1(int x, int now_top) {
top[x] = now_top;
pos[x] = ++tot;
if (son[x]) dfs1(son[x], now_top);
for (int i = 0; i< edge[x].size(); i++){
if (edge[x][i] == fa[x]) continue;
if (edge[x][i] != son[x]){
dfs1(edge[x][i], edge[x][i]);
}
}
}
int tr[maxn * 4];
void add(int l , int r , int p ,int a, int b){
if (l > a || r < a) return;
if (l == a && r == a){
tr[p] = b;
return ;
}
int mid = (l +r) / 2;
if (a <= mid) add(l, mid , p * 2 , a, b);
else add(mid +1, r, p*2+1, a, b);
tr[p] =tr[p *2] + tr[p * 2+1];
}
int query(int l, int r, int p , int a, int b){
if (l > b || r < a) return 0;
if(l >= a && r <=b){
return tr[p];
}
int mid = (l +r) /2;
if (b <= mid) return query(l, mid, p * 2, a, b);
else if (a > mid) return query(mid + 1, r, p *2 + 1, a, b);
else return query(l, mid, p * 2, a, b) + query(mid+1, r, p * 2 +1, a, b);
}
int ques_ans(int u, int v){
int f1 = top[u], f2 = top[v], ans = 0;
while (f1 != f2){
if (dep[f1] < dep[f2]){
swap(u, v);
swap(f1,f2);
}
ans += query(1, n, 1, pos[f1], pos[u]);
u = fa[f1];f1 = top[u];
}
if (u == v) return ans;
if (dep[u] > dep[v]) swap(u, v);
return ans + query(1, n, 1, pos[son[u]], pos[v]);
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i< n;i++){
int u, v, w;
scanf("%d%d%d", &u,&v,&w);
edge[u].push_back(v);
edge[v].push_back(u);
E[i].u = u;
E[i].v = v;
E[i].w = w;
}
sort(E+1,E+n, cmp2);
dfs(1, 1);
dfs1(1, 1);
for (int i = 1; i <= m;i++){
scanf("%d%d%d", &Q[i].l, &Q[i].r, &Q[i].k);
Q[i].id = i;
}
sort(Q+1, Q+1+m, cmp);
last = 0;
for (int i =1; i<=m;i++){
for (int j = last+1; j < n; j++){
if (E[j].w > Q[i].k) break;
if (dep[E[j].u] > dep[E[j].v]) swap(E[j].u, E[j].v);
add(1, n, 1, pos[E[j].v], 1);
last = j;
}
Ans[Q[i].id] = ques_ans(Q[i].l, Q[i].r);
}
for (int i = 1; i <= m;i++){
printf("%d\n", Ans[i]);
}
return 0;
}
AC的C++语言程序:
#include <bits/stdc++.h>
#define lo(i, n, m) for (int i = n; i < m; i++)
#define loe(i, n, m) for (int i = n; i <= m; i++)
#define rlo(i, n, m) for (int i = n - 1; i >= m; i--)
#define rloe(i, n, m) for (int i = n; i >= m; i--)
#define pb push_back
#define mk make_pair
#define clr(a, b) memset((a), (b), sizeof(a))
#define scd(x) scanf("%d", &x)
#define scs(x) scanf("%s", x)
#define sclf(x) scanf("%lf", &x)
#define scll(x) scanf("%lld", &x)
#define endl '\n'
using namespace std;
typedef long long LL;
template <class T>
inline void sw(T &a, T &b) {
T t = a;
a = b;
b = t;
}
template <class T>
inline T mx(T a, T b) {return b < a ? a : b;}
template <class T>
inline T mi(T a, T b) {return a < b ? a : b;}
template <class T>
inline T mabs(T x) {return x < 0 ? -x : x;}
inline char gc() {
char ch;
while ((ch = getchar()) == ' ' || ch == '\n' || ch == '\t');
return ch;
}
// Fast IO类
struct _IO {
char buf[20], ch;
_IO &operator >> (int &x) {
x = 0;
while ((ch = getchar()) < '0' || ch > '9');
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
return *this;
}
_IO &operator >> (long long &x) {
x = 0;
while ((ch = getchar()) <'0' || ch > '9');
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
return *this;
}
_IO &operator << (int x) {
int cur = 0;
if (!x) {
putchar('0');
return *this;
}
while (x) buf[cur++] = x % 10 + '0', x /= 10;
while (--cur >= 0) putchar(buf[cur]);
return *this;
}
_IO &operator << (long long x) {
int cur = 0;
if (!x) {
putchar('0');
return *this;
}
while (x) buf[cur++] = x % 10 + '0', x /= 10;
while (--cur >= 0) putchar(buf[cur]);
return *this;
}
_IO &operator << (char c) {
putchar(c);
return *this;
}
_IO &operator << (const char *str) {
for (int i = 0; str[i]; i++) putchar(str[i]);
return *this;
}
} IO;
const int NIL = -1;
const int LIM = 1e5 + 10;
const int SIZE = LIM << 1;
// 边的结构体
// 两个数组,edge[]是使用链式前向星存图用的数组(每条边会加入两个),eds用来存放单条边(相当于每条边只存放一次)
struct EDGE {
int u, nxt, v, w;
EDGE(int nid = 0, int nv = 0, int nw = 0) : nxt(nid), v(nv), w(nw) {}
bool operator < (const EDGE &e) const {
return w < e.w;
}
} edge[SIZE], eds[LIM];
// que存放队列,g是链式前向星定义的图的每个链的表头,
// idx[i]是树链剖分后结点i所在链中的位置,这里深度大的结点编号小
// dep[i]是结点i的深度
// sz[i]是结点i的子树的大小
// belong[i]是结点i所属的链的编号(从0开始)
// fa[i]是顶点i在链中的父结点
// head[i]是顶点i所在链中深度最小的结点
// len[i]是编号为i的链的长度
int que[LIM], g[LIM], idx[LIM], dep[LIM], sz[LIM], belong[LIM], fa[LIM], head[LIM], len[LIM];
bool vis[LIM];
// l和r标记队尾和队头
int l, r, cnt;
int ec = 0;
int n, m, u, v, w;
// 前向星加边函数
inline void add(int u, int v, int w) {
int pos = ec++;
edge[pos] = EDGE(g[u], v, w);
edge[pos].u = u;
g[u] = pos;
}
// BFS版树链剖分
inline void split() {
clr(dep, NIL);
l = 0, r = 1;
que[r] = 1;
dep[1] = 0;
fa[1] = NIL;
// start bfs
while (l < r) {
int x = que[++l];
vis[x] = false;
for (int i = g[x]; i != NIL; i = edge[i].nxt) {
if (dep[edge[i].v] == NIL) {
// push into queue
que[++r] = edge[i].v, dep[edge[i].v] = dep[x] + 1;
fa[edge[i].v] = x;
}
}
}
// do split
for (int i = n; i; i--) {
int x = que[i], p = NIL;
sz[x] = 1;
for (int j = g[x]; j != NIL; j = edge[j].nxt) {
if (vis[edge[j].v]) {
sz[x] += sz[edge[j].v];
if (p == NIL || sz[edge[j].v] > sz[p])
p = edge[j].v;
}
}
if (p == NIL) {
idx[x] = len[++cnt] = 1;
belong[head[cnt] = x] = cnt;
} else {
idx[x] = ++len[belong[x] = belong[p]];
head[belong[x]] = x;
}
vis[x] = true;
}
}
// 存储询问的结构体
struct QUE {
int u, v, w, id;
QUE(int nu = 0, int nv = 0, int nw = 0, int nid = 0) : u(nu), v(nv), w(nw), id(nid) {}
bool operator < (const QUE &q) const {
return w < q.w;
}
};
vector<QUE> ques;
// 存储答案的数组
int qans[LIM];
// 树链长度的前缀和,用来给每条树链中的结点进行编号,将问题转化为区间查询问题
int presum[LIM];
// 用来计算结点x在线段树中的编号
inline int ID(int x) {
return presum[belong[x] - 1] + idx[x];
}
// 线段树的结构体
struct Node {
int l, r, dat;
} sgtree[SIZE * 4];
// 线段树向上合并操作的实用函数
inline void pushup(int idx) {
sgtree[idx].dat = sgtree[idx << 1].dat + sgtree[idx << 1 | 1].dat;
}
// 构建线段树的实用函数
void buildUtil(int l, int r, int idx) {
Node &crt = sgtree[idx];
if (l == r) {
crt.l = l;
crt.r = r;
sgtree[idx].dat = 0;
return;
}
int mid = (l + r) >> 1;
buildUtil(l, mid, idx << 1);
buildUtil(mid + 1, r, idx << 1 | 1);
pushup(idx);
// push up left and right bound
crt.l = sgtree[idx << 1].l;
crt.r = sgtree[idx << 1 | 1].r;
}
// 构建线段树的接口函数
void build(int l, int r) {
// memset(sgtree, 0, sizeof sgtree);
buildUtil(l, r, 1);
}
// 单点更新实用函数
void updateUtil(int p, int val, int idx) {
Node &crt = sgtree[idx];
if (crt.l == crt.r) {
sgtree[idx].dat += val;
return;
}
int mid = (crt.l + crt.r) >> 1;
if (p <= mid) updateUtil(p, val, idx << 1);
else updateUtil(p, val, idx << 1 | 1);
pushup(idx);
}
// 单点更新的接口函数
inline void update(int p, int val) {
updateUtil(p, val, 1);
}
// 区间查询的实用函数
int queryUtil(int l, int r, int idx) {
Node &crt = sgtree[idx];
if (crt.l >= l && crt.r <= r) {
return crt.dat;
}
int mid = (crt.l + crt.r) >> 1;
if (r <= mid) return queryUtil(l, r, idx << 1);
else if (l > mid) return queryUtil(l, r, idx << 1 | 1);
else return queryUtil(l, mid, idx << 1) + queryUtil(mid + 1, r, idx << 1 | 1);
}
// 区间查询的接口函数
inline int query(int l, int r) {
if (l > r) sw(l, r);
return queryUtil(l, r, 1);
}
// 单点查询的实用函数
int queryUtil(int p, int idx) {
Node &crt = sgtree[idx];
if (crt.l == crt.r) {
return crt.dat;
}
int mid = (crt.l + crt.r) >> 1;
if (p <= mid) return queryUtil(p, idx << 1);
else return queryUtil(p, idx << 1 | 1);
}
// 单点查询的实用函数
inline int query(int p) {
return queryUtil(p, 1);
}
/**
* 树链剖分将结点编号,之后将边和询问按权值递增排序,离线查询
* 将当前加入的边标记为1,记录到深度较深的结点上,
* 问题转化为区间查询问题
*/
int main(void) {
IO >> n >> m;
clr(g, NIL);
lo(i, 1, n) {
IO >> u >> v >> w;
eds[i].u = u, eds[i].v = v, eds[i].w = w;
add(u, v, w), add(v, u, w);
}
split();
loe(i, 1, cnt) presum[i] = presum[i - 1] + len[i];
// 对边按权值排序
sort(eds + 1, eds + n);
// load querys
lo(i, 0, m) {
IO >> u >> v >> w;
ques.pb(QUE(u, v, w, i));
}
// 对询问按权值排序
sort(ques.begin(), ques.end());
int pos = 1;
build(1, presum[cnt]);
lo(i, 0, ques.size()) {
QUE &q = ques[i];
while (pos < n && eds[pos].w <= ques[i].w) {
EDGE &e = eds[pos++];
if (dep[e.u] > dep[e.v]) update(ID(e.u), 1);
else update(ID(e.v), 1);
}
if (belong[q.u] == belong[q.v]) {
if (dep[q.v] > dep[q.u]) sw(q.u, q.v);
qans[q.id] = query(ID(q.u), ID(q.v)) - query(ID(q.v));
} else {
while (belong[q.u] != belong[q.v]) {
if (dep[head[belong[q.v]]] > dep[head[belong[q.u]]]) sw(q.u, q.v);
qans[q.id] += query(ID(q.u), ID(head[belong[q.u]]));
q.u = fa[head[belong[q.u]]];
}
if (dep[q.v] > dep[q.u]) sw(q.u, q.v);
qans[q.id] += query(ID(q.u), ID(q.v)) - query(ID(q.v));
}
}
lo(i, 0, ques.size()) IO << qans[i] << endl;
return 0;
}
AC的C++语言程序:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<ctime>
#include<ctype.h>
#include<stdlib.h>
#include<bitset>
#include<algorithm>
#include<assert.h>
#include<numeric> //accumulate
#define endl "\n"
#define fi first
#define se second
#define FOR(i,s,t) for(int i=(s);i<=(t);++i)
#define mem(a,b) memset(a,b,sizeof(a))
#define rush() int MYTESENUM;scanf("%d",&MYTESENUM);while(MYTESENUM--)
#define debug(x) printf("%d\n",x)
using namespace std;
const int maxn=100000+10;
int n;
int pref[maxn];
int main()
{
cin.tie(0);
cout.tie(0);
//ios_base::sync_with_stdio(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
rush()
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&pref[i]);
}
for(int i=4;i<=n;i++)
{
pref[i]^=pref[i-4];
}
int q;
scanf("%d", &q);
while( q-- )
{
int l,r;
scanf("%d %d", &l, &r);
int len=r-l+1;
int ans;
if(len%4==0)
{
ans=0;
}
else if(len%4==1)
{
if(l>=4)
ans=pref[r]^pref[l-4];
else
ans=pref[r];
}
else if(len%4==2)
{
if(l>=3)
ans=pref[r]^pref[l-3];
else
ans=pref[r];
if(l>=4)
ans^=pref[r-1]^pref[l-4];
else
ans^=pref[r-1];
}
else
{
if(l>=3)
ans=pref[r-1]^pref[l-3];
else
ans=pref[r-1];
}
printf("%d\n", ans);
}
}
}
很暴力的:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
typedef long long ll;
ll T, n,q,le,ri,mid,ans,sum,k;
ll a[maxn], f[4][5][maxn],fu;
int main() {
cin >> T;
int g[4][4][4]={1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0};
while (T--){
scanf("%lld", &n);
sum = 0;
for (int i =1; i <= n; i++)
scanf("%lld", &a[i]), sum = sum ^ a[i];
for (int k = 0; k <4;k++)
for (int i = 0; i < 4; i++)
for (int j = 1; j <=n;j++)
f[k][i][j] = f[k][i][j-1]^(a[j]*g[k][i][(j-1)%4]);
scanf("%lld", &q);
while (q--){
scanf("%lld%lld", &le ,&ri) ;
mid = ri - le;
ans =sum;
printf("%lld\n", (f[(le-1)%4][mid%4][ri]^f[(le-1)%4][mid%4][le-1]) );
}
}
return 0;
}
L. qiqi’tree
几何模拟树的生长。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e6;
struct branch{
double x1, y1, x2, y2;
double getLength(){
return sqrt((x1 - x2) *(x1 - x2) + (y1 -y2) * (y1 - y2));
}
};
struct line{
double x0, y0, k;
}L;
int n;
int isUpLine(double x, double y, line L){
if (y > L.k * x - L.k * L.x0 + L.y0) return 1;
else if (y < L.k * x - L.k * L.x0 + L.y0) return -1;
return 0;
}
double dis(double x, double y, line L){
double ans = L.k * x - y - L.k * L.x0 + L.y0;
return fabs(ans) / sqrt(L.k * L.k +1);
}
double restLength(branch a, line b){
if (isUpLine(a.x1, a.y1, b) < 0 && isUpLine(a.x2, a.y2, b) == 0) return a.getLength();
if (isUpLine(a.x1, a.y1, b) < 0 && isUpLine(a.x2, a.y2, b) > 0) {
double l1 = dis(a.x1, a.y1, b);
double l2 = dis(a.x2, a.y2, b);
return a.getLength()*l1/(l1+l2);
}
}
branch q[maxn],nxt[maxn];
int tot, tot1;
double Ans =0;
void cut(){
for (int i = 0; i < tot; i++){
if (isUpLine(q[i].x1, q[i].y1, L) * isUpLine(q[i].x2, q[i].y2, L) >0){
Ans += q[i].getLength();
nxt[tot1++] = q[i];
}
else if (isUpLine(q[i].x1, q[i].y1, L) <0 && isUpLine(q[i].x2, q[i].y2, L) ==0){
Ans += q[i].getLength();
}else if (isUpLine(q[i].x1, q[i].y1, L) <0 && isUpLine(q[i].x2, q[i].y2, L) > 0){
Ans += restLength(q[i], L);
}
}
tot=0;
for (int i = 0; i < tot1; i++){
double x = (nxt[i].x2 - nxt[i].x1)/4;
double y = (nxt[i].y2 - nxt[i].y1)/4;
q[tot++] = {nxt[i].x2, nxt[i].y2, x+nxt[i].x2, y+nxt[i].y2};
q[tot++] = {nxt[i].x2, nxt[i].y2, 1.0/2.0 * x - sqrt(3.0)/2.0 * y + nxt[i].x2 , sqrt(3.0)/2.0 * x + 1.0/2.0*y + nxt[i].y2};
// cout <<q[tot-1].x1 << " " <<q[tot-1].y1<< " " << q[tot-1].x2 <<" "<< q[tot-1].y2 << endl;
q[tot++] = {nxt[i].x2, nxt[i].y2, 1.0/2.0 * x + sqrt(3.0)/2.0 * y + nxt[i].x2 , -sqrt(3.0)/2.0 * x + 1.0/2.0*y + nxt[i].y2};
}
tot1 =0;
}
int main()
{
int T;
cin >> T;
while (T--){
double len=0;tot=0,tot1=0;
scanf("%lf", &len);
scanf("%d%lf%lf%lf", &n, &L.x0, &L.y0, &L.k);
branch fir({0.0,0.0,0.0,len});
q[tot++] = fir;Ans =0;
for (int i = 1; i<=n;i++){
cut();
}
printf("%.6lf\n", Ans);
}
return 0;
}
AC的C++语言程序:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<ctime>
#include<ctype.h>
#include<stdlib.h>
#include<bitset>
#include<algorithm>
#include<assert.h>
#include<numeric> //accumulate
#define endl "\n"
#define fi first
#define se second
#define FOR(i,s,t) for(int i=(s);i<=(t);++i)
#define mem(a,b) memset(a,b,sizeof(a))
#define rush() int MYTESENUM;scanf("%d",&MYTESENUM);while(MYTESENUM--)
using namespace std;
const int maxn=100000+5;
char s[maxn];
char t[maxn];
int f[maxn][30];
inline bool check()
{
int p=1;
for(int i=1;t[i];i++)
{
p=f[p][t[i]-'a'];
if(p==0)
return 0;
p++;
}
return 1;
}
int main()
{
cin.tie(0);
cout.tie(0);
//ios_base::sync_with_stdio(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
scanf("%s",s+1);
int n=strlen(s+1);
for(int i=n;i;i--)
{
for(int j=0;j<26;j++)
{
if(s[i]==j+'a')
{
f[i][j]=i;
}
else
{
f[i][j]=f[i+1][j];
}
}
}
rush()
{
scanf(" %s",t+1);
if(check())
puts("YES");
else
puts("NO");
}
}
预处理第一串st[i]后26个字符第一次出现的地方。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
char st[maxn], st2[1002];
int now[26], nxt[maxn][26];
int n;
int main() {
scanf("%s" , st);
int l1 = strlen(st);
for (int i = 0 ; i < 26; i++) now[i] = l1;
for (int i = l1 -1 ; i >=0; i--){
for (int j = 0; j < 26;j++){
nxt[i][j] = now[j];
}
now[st[i] - 'a'] = i;
}
scanf("%d", &n);
for (int i = 0;i <n;i++){
scanf("%s", st2);
int l2 = strlen(st2);
int s1, s2;
s1 = s2 = 0;
if (l2 > l1) {
printf("NO\n");
continue;
}
s1 = now[st2[0] - 'a'];
for (int j = 1; j < l2; j++){
s1 = nxt[s1][st2[j] -'a'];
if (s1 == l1) break;
}
if (s1 != l1) printf("YES\n");
else printf("NO\n");
}
return 0;
}
参考链接:
The Preliminary Contest for ICPC China Nanchang National Invitational 南昌网络赛2019
2019南昌邀请赛网络赛 个人记录(附官方题解)