场上解决:C,D,F
已补题: A,B,G,H,J,K
字符串
给你n个字符串,定义 f ( s , t ) f(s,t) f(s,t)表示串s的前缀和t的后缀的最长匹配长度求:
∑ i = 1 n ∑ j = 1 n f ( s i , s j ) 2 ( m o d 998244353 ) \sum_{i=1}^{n}\sum_{j=1}^{n}f(s_i,s_j)^2(mod\ 998244353) i=1∑nj=1∑nf(si,sj)2(mod 998244353)
hash字符串的后缀,利用map计数,枚举每个字符串的前缀,找到多少个与之匹配的后缀,但对于同一个字符串,倘若前缀a,为前缀b的后缀,应该只计算前缀b,这显然就是 k m p kmp kmp的next数组。枚举时对每个字符串从前往后枚举
c n t [ i ] = m a p [ h a s h ( p r e ( i ) ) ] , c n t [ n e x t [ i ] ] − = c n t [ i ] cnt[i] = map[hash(pre(i))],cnt[next[i]]-=cnt[i] cnt[i]=map[hash(pre(i))],cnt[next[i]]−=cnt[i]
#include
#define ll long long
#define ull unsigned long long
#define pb push_back
#define lowbit(x) ((x)&(-x))
#define inf 0x3f3f3f3f
#define endl "\n"
#define MP(x,y) (make_pair(x,y))
#define pii pair
#define pll pair
#define pi 3.1415926535
using namespace std;
const int mod = 998244353;
ll d[1000005];
string s[100005];
char p[1000005];
int n;
map num;
int Next[1000005];
ll cnt[1000005];
int b;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
d[0] = 1;
b = 113;
for(int i=1;i<1000002;i++){
d[i] = d[i-1]*b;
}
cin>>n;
for(int i=0;i>s[i];
int len = s[i].length();
ll val = 0;
for(int j = len-1;j>=0;j--){
val+=d[len-j-1]*(s[i][j]-'a'+1);
num[val]++;
}
}
ll ans = 0;
for(int k=0;k 0 && p[i] != p[j+1]) j=Next[j];
if(p[i] == p[j+1]) j++;
Next[i]=j;
val*=b;
val+=p[i]-'a'+1;
cnt[i] = num[val];
if(j) cnt[j] -= cnt[i];
}
for(ll j=1;j<=m;j++){
ans+=1ll*cnt[j]%mod*(j)%mod*(j)%mod;
ans %= mod;
}
}
cout<
计算几何
给你n个点,保证不重复且不在原点,求在所有经过原点的圆中,圆上给定点最多的数目是多少
将每个点与原点相连,得到这条线段的垂直平分线,共有n条,n条垂直平分线两两相交得到可能的圆心,统计一个圆心出现的次数,次数最多的圆心所在圆即答案所在圆,计算这个圆心所在圆上的给定点数目(注意判断共线问题和一个点的情况);
#include
#define ll long long
#define ull unsigned long long
#define pb push_back
#define lowbit(x) ((x)&(-x))
#define inf 0x3f3f3f3f
#define endl "\n"
#define MP(x,y) (make_pair(x,y))
#define pll pair
#define pi 3.1415926535
using namespace std;
const double eps = 1e-6;
int n,tot;
struct nodi{
int x,y;
}a[2005];
struct nodd{
double x,y;
}b[5000005];
bool cmp(nodd a,nodd b){
if(fabs(a.x - b.x)
贪心,树
给你一颗树,用最少的链覆盖所有的边
答案显然是将叶子两两相连,数目是 ⌈ 叶 子 数 目 / 2 ⌉ \lceil叶子数目/2\rceil ⌈叶子数目/2⌉,考虑如何构造解,
或者可以考虑随机算法,随机若干次直到满足。
签到题,模拟
给你一天的两个时刻,求相差的秒数
全部化成秒,相减取绝对值
FWT
给你n个整数, A 1 , A 2 , . . . , A n A_1,A_2,...,A_n A1,A2,...,An,输出i个数,第i个数为从给你的数中选出i个数的异或值的最大值,可以重复选择
小范围暴力,大范围规律,对于 i > 19 i>19 i>19之后有 a n s i = a n s i − 2 ans_i =ans_{i-2} ansi=ansi−2,因为A< 2 18 2^{18} 218,所以最多第19轮达到满秩,小范围暴力可以依靠异或卷积FWT完成
#include
#define ll long long
#define ull unsigned long long
#define pb push_back
#define lowbit(x) ((x)&(-x))
#define inf 0x3f3f3f3f
#define endl "\n"
#define MP(x,y) (make_pair(x,y))
#define pii pair
#define pll pair
using namespace std;
const int N = (1<<18);
const int MOD = 998244353;
ll qpow(ll a,ll b){
ll res = 1;
while(b){
if(b&1) res = res * a % MOD;
b>>=1;
a = a*a%MOD;
}
return res;
}
int inv2 ;
void FWT_xor(ll *a,int opt)
{
for(int i=1;i=0;j--){
if(b[j]){
ans[i] = j;
break;
}
}
}
for(int i=21;i<=n;i++) ans[i] = ans[i-2];
for(int i=1;i<=n;i++){
if(i>1) printf(" ");
printf("%d",ans[i]);
}
}
签到,模拟,优化
给定一个 n ∗ m n*m n∗m的矩阵,第 ( i , j ) (i,j) (i,j)个位置的值为 l c m ( i , j ) lcm(i,j) lcm(i,j),有一个 k ∗ k k*k k∗k的框在矩阵内移动,求这个框在所有位置的最大值的和
g c d gcd gcd写记忆化,滑动窗口维护最大值
b i t s e t bitset bitset 优化
给你一个长度为n的序列A,和一个长度为m的序列B,求有多少长为m的A的子序列S,满足 ∀ i ∈ { 1 , 2 , . . . m } , S i > B i \forall i\in\{1,2,...m\},S_i>B_i ∀i∈{1,2,...m},Si>Bi
#include
#define ll long long
#define ull unsigned long long
#define pb push_back
#define lowbit(x) ((x)&(-x))
#define inf 0x3f3f3f3f
#define endl "\n"
#define MP(x,y) (make_pair(x,y))
#define pii pair
#define pll pair
#define pi 3.1415926535
using namespace std;
int n,m;
int a[150005];
struct nd{
int val,id;
}b[40005];
bitset<40005> s,ss[40005],cur;
int fd(int x){
int l = 0,r = m;
while(l>1;
if(b[mid].val> x) r = mid;
else l = mid+1;
}
return l;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i
数据结构
给你一个multiset,三个操作,操作一为插入一个元素x,操作二为删除一个元素x,操作三位判断multiset中是否有两个数与x构成一个不退化三角形
判断能否构成三角形,有两种情况,一是x为最长边,则存在两条边 a + b > x a+b>x a+b>x使用小于等于x的最大的两条边判断即可,这里可以用set+map维护,set存在集合中的数,map存各个数的数量。
二是x为非最长边,即存在 a − b < x a-b
#include
#define ll long long
#define ull unsigned long long
#define pb push_back
#define lowbit(x) ((x)&(-x))
#define inf 0x3f3f3f3f
#define endl "\n"
#define MP(x,y) (make_pair(x,y))
#define pii pair
#define pll pair
#define pi 3.1415926535
using namespace std;
const int INF = 2*inf;
const int maxn = 2e5+5;
struct ask{
int op,x;//,id;
}a[maxn];
int b[maxn],q,m;
set s;
map mp;
struct stree{
int l,r;
int val;
}t[maxn<<2];
void pushup(int x){
t[x].val = min(t[x<<1].val,t[x<<1|1].val);
}
void build(int x,int l,int r){
t[x].l = l,t[x].r = r;
if(l == r){
t[x].val = INF;
return;
}
int mid = (t[x].l+t[x].r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
pushup(x);
}
void change(int x,int p,int val){
if(t[x].l == t[x].r){
t[x].val = val;
return;
}
int mid = (t[x].l+t[x].r)>>1;
if(p<=mid) change(x<<1,p,val);
else change(x<<1|1,p,val);
pushup(x);
}
int query(int x,int l,int r){
if(t[x].l>=l && t[x].r<=r){
return t[x].val;
}
int mid = (t[x].l+t[x].r)>>1;
int res = INF;
if(mid>=l) res = min(res,query(x<<1,l,r));
if(mid1){
mx += *it;
}else{
it--;
mx += *it;
if(*it == -1)
f=0;
}
}
if(mx > x && f){
puts("Yes");
}else{
int mn = query(1,p,m);
if(x>mn){
puts("Yes");
}else{
puts("No");
}
}
}
}
}
网格网络流
给你元组(l,r),可以进行缩减和扩张操作,你可以花一些费用禁止一些操作。求最小的费用使得 l ! = r l!=r l!=r.
裸的网格图网络流,对偶图最短路=最小割
#include
#define ll long long
#define ull unsigned long long
#define pb push_back
#define lowbit(x) ((x)&(-x))
#define inf 0x3f3f3f3f
#define endl "\n"
#define MP(x,y) (make_pair(x,y))
#define pii pair
#define pll pair
using namespace std;
const int N=500010;
vector ver[N],edge[N];
ll d[N];//到起点的距离
bool v[N];
int n,m,s,t;
priority_queue > q;//第一维为-d[x],第二维为x
void dijkstra(){
memset(d,0x3f,sizeof(d));
d[s]=0;
q.push(make_pair(0,s));
// cout<d[x]+z){
d[y]=d[x]+z;
q.push(make_pair(-d[y],y));
}
}
}
}
void add(int x,int y,ll w){
ver[x].pb(y),ver[y].pb(x);
edge[x].pb(w),edge[y].pb(w);
}
int id[505][505];
int tot;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i= d[N-1]){
puts("-1");
}else{
printf("%lld\n",d[t]);
}
}
数学
给定一个 1 1 1~ n n n的排列A,求一个置换B,使得 1 , 2 , 3... n {1,2,3...n} 1,2,3...n经过k轮置换变成A
对每个环,长度为r,即周期为r,假设{ a 1 , a 2 . . . , a r a_1,a_2...,a_r a1,a2...,ar}( a 1 < a 2 < . . . < a r a_1
#include
#define ll long long
#define ull unsigned long long
#define pb push_back
#define lowbit(x) ((x)&(-x))
#define inf 0x3f3f3f3f
#define endl "\n"
#define MP(x,y) (make_pair(x,y))
#define pii pair
#define pll pair
#define pi 3.1415926535
using namespace std;
const int N = 1e5+5;
int a[N],used[N],ans[N],tmp[N];
vector seq;
int n,m;
ll ex_gcd(ll a, ll b, ll &x, ll &y) {
if (b == 0) {
x = 1, y = 0;
return a;
}
else {
ll r = ex_gcd(b, a % b, y, x);
y -= x * (a / b);
return r;
}
}
ll inv(ll a, ll p) {//a在模p意义下的逆元若gcd(a,p)!=1,逆元不存在
ll x, y;
ex_gcd(a, p, x, y);
x = (x % p + p) % p;
return x;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++){
if(!used[i]){//若之前已经出现在某个环上不操作
seq.clear();
int now = i;
//找环
while(!used[now]){
seq.pb(now);
used[now] = 1;
now = a[now];
}
int k = inv(m%seq.size(),seq.size());
for(int j=0;j1) printf(" ");
printf("%d",ans[i]);
}
return 0;
}
期望,积分,计算几何
给你三个同心圆,从各圆中任取一点,求这三个点构成三角形面积的期望
固定A点,枚举B点。AB都固定的情况下显然可以积分算出ABC三角形以AB为底的高的期望
对于一个固定的 AB,我们可以求出线段长度 L 以及它与圆心的距离 H 和夹角 α ,显然有 a l p h a < π 2 alpha < \frac{\pi}{2} alpha<2π
接着通过积分求出 C 点运动时这个三角形的期望高,我们将其分成三部分。
s u m 1 = ∫ 0 π ( H + r 3 × s i n ( x ) ) d x = π H + r 3 × ∫ 0 π s i n ( x ) d x = π H + 2 × r 3 sum_1=\int_{0}^{\pi}(H+r3\times sin(x))dx=\pi H + r3\times \int_{0}^{\pi}sin(x)dx=\pi H+2\times r3 sum1=∫0π(H+r3×sin(x))dx=πH+r3×∫0πsin(x)dx=πH+2×r3
s u m 2 = 2 ∫ 0 α ( H − r 3 × s i n ( x ) ) d x = 2 ( H α − r 3 ∫ 0 α s i n ( x ) d x ) = 2 ( α H + r 3 × c o s ( α ) − r 3 ) sum_2=2\int_{0}^{\alpha}(H-r3\times sin(x))dx=2(H\alpha - r3\int_{0}^{\alpha}sin(x)dx)=2(\alpha H +r3\times cos(\alpha)-r3) sum2=2∫0α(H−r3×sin(x))dx=2(Hα−r3∫0αsin(x)dx)=2(αH+r3×cos(α)−r3)
s u m 3 = ∫ α π − α ( r 3 × s i n ( x ) − H ) d x = r 3 ∫ α π − α s i n ( x ) d x − ( π − 2 α ) H = 2 r 3 × c o s ( α ) − ( π − 2 α ) H sum_3=\int_{\alpha}^{\pi-\alpha}(r3\times sin(x)-H)dx=r3\int_{\alpha}^{\pi-\alpha}sin(x)dx-(\pi-2\alpha)H=2r3\times cos(\alpha)-(\pi-2\alpha)H sum3=∫απ−α(r3×sin(x)−H)dx=r3∫απ−αsin(x)dx−(π−2α)H=2r3×cos(α)−(π−2α)H
故
s u m = π H + 2 × r 3 + 2 ( α H + r 3 × c o s ( α ) − r 3 ) + 2 r 3 × c o s ( α ) − ( π − 2 α ) H = 4 r 3 × c o s ( α ) + 4 α × H sum=\pi H+2\times r3+2(\alpha H +r3\times cos(\alpha)-r3)+2r3\times cos(\alpha)-(\pi-2\alpha)H=4r3\times cos(\alpha)+4\alpha\times H sum=πH+2×r3+2(αH+r3×cos(α)−r3)+2r3×cos(α)−(π−2α)H=4r3×cos(α)+4α×H
所以期望高度 h = 4 r 3 × c o s ( α ) + 4 α × H 2 π h=\frac{4r3\times cos(\alpha)+4\alpha\times H}{2\pi} h=2π4r3×cos(α)+4α×H,期望面积为 h × L 2 \frac{h\times L}{2} 2h×L
在圆周上均匀取1000个B点即可
#include
#define ll long long
#define ull unsigned long long
#define pb push_back
#define lowbit(x) ((x)&(-x))
#define inf 0x3f3f3f3f
#define endl "\n"
#define MP(x,y) (make_pair(x,y))
#define pii pair
#define pll pair
using namespace std;
const double pi = acos(-1.0);
int t;
int r1,r2,r3;
double f(double x){
return x*x;
}
void gao(){
scanf("%d%d%d",&r1,&r2,&r3);
if (r1 > r2) swap(r1, r2);
if (r1 > r2) swap(r1, r3);
if (r2 > r3) swap(r2, r3);
double ans = 0;
for(int i=1;i<=1000;i++){
double sina = sin(2.0 * pi / 1000.0 * i);
double cosa = cos(2.0 * pi / 1000.0 * i);
double x = r2*cosa,y = r2*sina;
double l = sqrt(f(x-r1)+f(y));
double h = y/l*r1;
double alpha = asin(h/r3);
double H = (4.0*r3*cos(alpha) + 4.0*alpha*h)/(2.0*pi);
ans += H*l/2;
}
ans /= 1000.0;
printf("%.1f\n",ans);
}
int main(){
scanf("%d",&t);
while(t--){
gao();
}
}