比赛链接
温暖的签到题。
#include
using namespace std;
int a, b, n;
int main()
{
scanf("%d%d%d", &a, &b, &n);
int x = 0, y = 0, cnt = 0;
while(x+b!=n||y+a!=n)
{
y = min(n-a, x + b - a);
++cnt;
if(x+b==n&&y+a==n) break;
x = min(n-b, y);
++cnt;
}
printf("%d\n", cnt);
return 0;
}
考虑在一个函数的单调的半周期上寻找一个上升的序列,且要求尽可能小。寻找一个最接近极值的即可。
#include
using namespace std;
const double pi = acos(-1.0);
int x[50005];
int main()
{
x[1] = 11;
for(int i=2; i<=50000; i++) x[i] = x[i-1] + 710;
reverse(x+1, x+50001);
int n; scanf("%d", &n);
for(int i=1; i<=n; i++) printf("%d\n", x[i]);
return 0;
}
考虑对于每个,连四条边,左上角-左下角,左上角-右下角,右上角-左下角,右上角-右下角。求欧拉回路即可。
注意欧拉回路上的边要求斜边和竖直边交错。输出时只输出去掉一条竖直边的欧拉路即可。
#include
using namespace std ;
const int maxn = 100 + 10 ;
int n , m ;
char s[maxn][maxn] ;
int id(int x , int y)
{
return x * (m + 1) + y + 1 ;
}
struct Link
{
int num , head[2][maxn * maxn] ;
bool vis[maxn * maxn * 20] ;
vector> ans ;
struct Edge
{
int v , w , next ;
} edge[2][maxn * maxn * 20] ;
void init()
{
num = 0 ;
memset(head , 0 , sizeof(head)) ;
}
void add_edge(int u , int v , int w , int op)
{
num ++ ;
edge[op][num].v = v ;
edge[op][num].w = w ;
edge[op][num].next = head[op][u] ;
head[op][u] = num ;
}
void add(int u , int v , int w , int op)
{
add_edge(u , v , w , op) ;
add_edge(v , u , -w , op) ;
}
void dfs(int u , int op)
{
//cout << op << ' ' << u << ' ' << head[op][u] << '\n' ;
for(int &i = head[op][u] ; i != 0 ; i = edge[op][i].next) //需要引用,自动删边
{
int v = edge[op][i].v ;
int w = edge[op][i].w ;
if(vis[abs(w)]) continue ;
vis[abs(w)] = true ;
dfs(v , 1 - op) ;
ans.push_back({u , v}) ;
}
}
void print()
{
int siz = ans.size() ;
reverse(ans.begin() , ans.end()) ;
bool flag = false ;
cout << siz - 1 << '\n' ;
for(int i = 0 ; i < siz - 1 ; i ++)
{
int u = ans[i].first ;
int v = ans[i].second ;
if(!flag)
{
flag = true ;
int ux = (u - 1) / (m + 1) ;
int uy = (u - 1) % (m + 1) ;
int vx = (v - 1) / (m + 1) ;
int vy = (v - 1) % (m + 1) ;
cout << uy << ' ' << ux << '\n' ;
cout << vy << ' ' << vx << '\n' ;
}
else
{
int vx = (v - 1) / (m + 1) ;
int vy = (v - 1) % (m + 1) ;
cout << vy << ' ' << vx << '\n' ;
}
}
}
} link ;
int main()
{
std::ios::sync_with_stdio(false) , cin.tie(0) ;
cin >> m >> n ;
for(int i = 1 ; i <= n ; i ++) cin >> s[i] + 1 ;
int cnt = 0 ;
link.init() ;
for(int i = 1 ; i <= n ; i ++) for(int j = 1 ; j <= m ; j ++)
if(s[i][j] == 'X')
{
link.add(id(i , j) , id(i - 1 , j - 1) , ++ cnt , 0) ;
link.add(id(i , j - 1) , id(i - 1 , j) , ++ cnt , 0) ;
link.add(id(i - 1 , j - 1) , id(i , j - 1) , ++ cnt , 1) ;
link.add(id(i - 1 , j) , id(i , j) , ++ cnt , 1) ;
}
for(int i = 1 ; i <= n ; i ++) for(int j = 1 ; j <= m ; j ++)
if(s[i][j] == 'X')
{
link.dfs(id(i , j) , 0) ;
link.print() ;
return 0 ;
}
return 0 ;
}
好题。思路见注释。
#include
using namespace std ;
const int mod = 998244353 ;
long long qpow(long long a , long long b) //快速幂
{
if(b < 0) return 0 ;
long long ans = 1 ;
a %= mod ;
while(b)
{
if(b & 1) ans = (ans * a) % mod ;
b >>= 1 , a = (a * a) % mod ;
}
return ans % mod ;
}
int main()
{
//需要发现一个现象,如果s可以划分为多种双回文串,即s=s1+s2=s3+s4,其中s1,s2,s3,s4都是回文串。
//那么s=t+t+t+t+t+t+t,其中t是划分唯一的双回文串
//f[i]表示长度是i的双回文串的划分个数
//暴力算就好了
//g[i]表示长度是i的划分唯一的字符串个数
//g[i] = f[i] - i / j * g[j] , i % j = 0
//通过g[i]暴力算答案
//ans = \sigma_i=1^n g[i] * (n / i)
std::ios::sync_with_stdio(false) , cin.tie(0) ;
int n , k ;
cin >> n >> k ;
vector f(n + 1 , 0) ;
vector g(n + 1 , 0) ;
for(int i = 1 ; i <= n ; i ++)
{
if(i % 2 == 1) f[i] = i * qpow(k , (i + 1) / 2) ;
else f[i] = (i / 2) * qpow(k , i / 2) + (i / 2) * qpow(k , i / 2 + 1) ;
}
for(int i = 1 ; i <= n ; i ++) g[i] = f[i] ;
for(int j = 1 ; j <= n ; j ++)
{
for(int i = j + j ; i <= n ; i += j)
{
g[i] -= i / j * g[j] % mod ;
g[i] %= mod ;
}
}
long long ans = 0 ;
for(int i = 1 ; i <= n ; i ++) ans += 1ll * n / i * g[i] , ans %= mod ;
ans = (ans + mod) % mod ;
cout << ans << '\n' ;
return 0 ;
}
换根计算每个点到关键点的路径长度的最大值和最小值,如果最大值和最小值相等,那么到每个关键点的路径全相等。
#include
using namespace std;
const int N = 2e5 + 5, inf = 1e9;
int n, m;
vector G[N];
bool tag[N];
int mx[N], mn[N], mx2[N], mn2[N];
inline void Max(int &x, int y) { if(xy) x = y; }
void dfs(int u, int fa)
{
mx[u] = -inf, mn[u] = inf;
if(tag[u]) mn[u] = mx[u] = 0;
for(int v : G[u])
{
if(v==fa) continue;
dfs(v, u);
Max(mx[u], mx[v]+1);
Min(mn[u], mn[v]+1);
}
}
void dfs2(int u, int fa)
{
int smx = -inf, smx2 = -inf, smn = inf, smn2 = inf;
for(int v : G[u])
{
if(v==fa) continue;
if(mx[v]>smx) smx2 = smx, smx = mx[v];
else if(mx[v]>smx2) smx2 = mx[v];
if(mn[v]
留坑。
留坑。
根号分治即可,注意划分块的大小要合理。
#include
using namespace std;
const int N = 2e5 + 5, B = 600;
int n, q, a[N], sum[N];
int nxt[N][B], ans[B];
inline void read(int &x)
{
x = 0;
char c = getchar();
while(c>'9'||c<'0') c = getchar();
while(c>='0'&&c<='9') x = x*10 + c - 48, c = getchar();
}
void init(int s)
{
int j = 1;
for(int i=1; i<=n; i++)
{
while(j<=n && sum[j]-sum[i-1]<=s) ++j;
nxt[i][s] = j;
}
int p = 1, cnt = 0;
while(p<=n)
{
p = nxt[p][s];
++cnt;
}
ans[s] = cnt;
}
inline int jump(int p, int t) { return upper_bound(sum+p, sum+n+1, sum[p-1]+t) - sum; }
int main()
{
read(n);
int mx = 0;
for(int i=1; i<=n; i++) read(a[i]), sum[i] = sum[i-1] + a[i], mx = max(mx, a[i]);
for(int i=mx; i<=B; i++) init(i);
read(q);
while(q--)
{
int t; read(t);
if(t
二分金字塔的高度,考虑如何。
容易发现对于一个固定的金字塔的高度和一个固定的柱子,可行的金字塔中心的区域是正方形。原因是金字塔的等高线向地面的投影是正方形。
正方形的交集包含至少一个整数点即可。
#include
using namespace std;
#define M 1005
struct node{
int x,y,h;
}s[M];
int xl,yl,xr,yr;
bool In(int x,int y){
return x>=xl&&x<=xr&&y>=yl&&y<=yr;
}
int n;
node check(int H){
xl=-1e8,yl=-1e8,xr=1e8,yr=1e8;
for(int i=1;i<=n;i++){
int r=(H-s[i].h);
int x1=s[i].x-r,y1=s[i].y-r;
int x2=s[i].x+r,y2=s[i].y+r;
if(x1<=xl&&x2>=xr||y1<=yl&&y2>=yr){
swap(x1,xl);
swap(x2,xr);
swap(y1,yl);
swap(y2,yr);
}
if(In(x1,y1)&&In(x2,y2)){
xl=x1;yl=y1;
xr=x2;yr=y2;
}
else if(In(x1,y1)&&In(x1,y2)){
xl=x1;
yl=y1;yr=y2;
}
else if(In(x1,y1)&&In(x2,y1)){
xl=x1;xr=x2;
yl=y1;
}
else if(In(x2,y2)&&In(x1,y2)){
xl=x1;xr=x2;
yr=y2;
}
else if(In(x2,y2)&&In(x2,y1)){
xr=x2;
yl=y1;yr=y2;
}
else if(In(x1,y1)){
xl=x1;yl=y1;
}
else if(In(x1,y2)){
xl=x1;yr=y2;
}
else if(In(x2,y1)){
xr=x2;yl=y1;
}
else if(In(x2,y2)){
xr=x2;yr=y2;
}
else if(x1>=xl&&x2<=xr&&yl>=y1&&yr<=y2){
xl=x1;
xr=x2;
}
else if(y1>=yl&&y2<=yr&&xl>=x1&&xr<=x2){
yl=y1;
yr=y2;
}
else {
return (node){0,0,-1};
}
}
return (node){xl,yl,H};
}
int main(){
scanf("%d",&n);
int l=1,r=1e9;
for(int i=1;i<=n;i++){
scanf("%d %d %d",&s[i].x,&s[i].y,&s[i].h);
l=max(l,s[i].h);
}
node res;
while(l<=r){
int mid=l+r>>1;
node tmp=check(mid);
if(tmp.h!=-1){
res=tmp;
r=mid-1;
}
else l=mid+1;
}
printf("%d %d %d\n",res.x,res.y,res.h);
return 0;
}
对于的路径,枚举的。直接冲!
#include
using namespace std;
#define M 505
char str[M][M];
int a[M][M],G[M][M];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",str[i]+1);
for(int j=1;j<=n;j++)a[i][j]=str[i][j]-'0';
}
for(int l=1;l
首先通过悬线法求出包含的最大子矩阵。然后对于其他部分,从上往下扫一遍即可。
#include
using namespace std;
const int N = 1e3 + 5;
int n, m, a[N][N], ax, ay;
int up[N][N], dwn[N][N], l[N][N], r[N][N];
int dl[N], dr[N];
char s[N][N], t[N][N];
void work(int u, int d, int l, int r)
{
if(u>d || l>r) return;
int pre = u - 1;
for(int i=u; i<=d; i++)
{
bool fl = 0;
for(int j=l; j<=r; j++) if(isalpha(s[i][j])) fl = 1;
if(!fl) continue;
int p = l - 1;
for(int j=l; j<=r; j++)
if(isalpha(s[i][j]))
{
for(int k=p+1; k0; j--)
if(a[i][j]&&a[i][j+1]) r[i][j] = r[i][j+1];
dl[ax] = l[ax][ay], dr[ax] = r[ax][ay];
for(int i=ax-1; i>=1; i--)
{
dl[i] = max(dl[i+1], l[i][ay]);
dr[i] = min(dr[i+1], r[i][ay]);
}
for(int i=ax+1; i<=n; i++)
{
dl[i] = max(dl[i-1], l[i][ay]);
dr[i] = min(dr[i-1], r[i][ay]);
}
int ans = 1, L = ay, R = ay, U = ax, D = ax;
for(int up=1; ax-up+1>=1; up++)
{
int x = ax - up + 1;
if(!a[x][ay]) break;
for(int dwn=1; ax+dwn-1<=n; dwn++)
{
int y = ax + dwn - 1;
if(!a[y][ay]) break;
int cl = max(dl[x], dl[y]), cr = min(dr[x], dr[y]);
if((cr-cl+1)*(y-x+1)>ans) ans = (cr-cl+1)*(y-x+1), L = cl, R = cr, U = x, D = y;
}
}
for(int i=U; i<=D; i++)
for(int j=L; j<=R; j++) t[i][j] = 'a';
t[ax][ay] = 'A';
work(1, U-1, 1, m);
work(U, D, 1, L-1);
work(U, D, R+1, m);
work(D+1, n, 1, m);
}
int main()
{
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++) scanf("%s", s[i]+1);
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
{
if(s[i][j]=='.'||s[i][j]=='A') a[i][j] = 1;
else a[i][j] = 0;
if(s[i][j]=='A') ax = i, ay = j;
}
gao();
for(int i=1; i<=n; i++) printf("%s\n", t[i]+1);
return 0;
}
这个题就是的强化了一点点的版本。
唯一区别就是用数组特判一下的部分即可。
#include
using namespace std ;
const int maxn = 2e5 + 10 ;
struct Sa //如果是多个测例,记得清空 s
{
int rk[maxn << 1] , sa[maxn << 1] , height[maxn << 1] ;
int tmp[maxn << 1] , cnt[maxn] ;
char s[maxn] ;
int st[maxn][25] ;
void cal(int n , int m)
{
n ++ ;
for(int i = 0 ; i < n * 2 + 5 ; i ++)
rk[i] = sa[i] = height[i] = tmp[i] = 0 ;//开2 倍空间
for(int i = 0 ; i < m ; i ++) cnt[i] = 0 ;
for(int i = 0 ; i < n ; i ++) cnt[rk[i] = s[i]] ++ ;
for(int i = 1 ; i < m ; i ++) cnt[i] += cnt[i - 1] ;
for(int i = 0 ; i < n ; i ++) sa[-- cnt[rk[i]]] = i ;
for(int k = 1 ; k <= n ; k <<= 1)
{
int j = 0 ;
for(int i = 0 ; i < n ; i ++)
{
j = sa[i] - k ;
if(j < 0) j += n ;
tmp[cnt[rk[j]] ++] = j ;
}
sa[tmp[cnt[0] = 0]] = j = 0 ;
for(int i = 1 ; i < n ; i ++)
{
if(rk[tmp[i]] != rk[tmp[i - 1]]
|| rk[tmp[i] + k] != rk[tmp[i - 1] + k])
cnt[++ j] = i ;
sa[tmp[i]] = j ;
}
memcpy(rk , sa , n * sizeof(int)) ;
memcpy(sa , tmp , n * sizeof(int)) ;
if(j >= n - 1) break ;
}
height[0] = 0 ;
for(int i = 0 , k = 0 , j = rk[0] ; i < n - 1 ; i ++ , k ++)
while(~k && s[i] != s[sa[j - 1] + k])
height[j] = k -- , j = rk[sa[j] + 1] ;
}
void build_lcp(int n)
{
for(int i = 1 ; i <= n ; i ++) st[i][0] = height[i] ;
for(int j = 1 ; j <= 20 ; j ++)
for(int i = 1 ; i + (1 << j) - 1 <= n ; i ++)
st[i][j] = min(st[i][j - 1] , st[i + (1 << (j - 1))][j - 1]) ;
}
int lcp(int l , int r)
{
if(l > r) swap(l , r) ;
l ++ ;
int len = log2(r - l + 1) ;
return min(st[l][len] , st[r - (1 << len) + 1][len]) ;
}
} sa[2] ;
int main()
{
std::ios::sync_with_stdio(false) , cin.tie(0) ;
cin >> sa[0].s ;
int len = strlen(sa[0].s) ;
for(int i = 0 ; i < len ; i ++) sa[1].s[i] = sa[0].s[len - 1 - i] ;
sa[0].cal(len , 200) ;
sa[0].build_lcp(len) ;
sa[1].cal(len , 200) ;
sa[1].build_lcp(len) ;
auto rev = [&](int x)
{
return len - 1 - x ;
} ;
pair ans = {1 , 1} ;
for(int i = 2 ; i <= len ; i ++)
{
int res1 = abs(sa[0].sa[i] - sa[0].sa[i - 1]) + sa[0].height[i] ;
int res2 = abs(sa[0].sa[i] - sa[0].sa[i - 1]) ;
if(1ll * res1 * ans.second > 1ll * res2 * ans.first) ans = {res1 , res2} ;
}
for(int i = 1 ; i <= len ; i ++)
{
for(int j = 0 ; j < len ; j += i)
{
int p = j ;
while(p + i < len && sa[0].lcp(sa[0].rk[p] , sa[0].rk[p + i]) >= i) p += i ;
if(p + i - 1 <= len - 1 && (p == j || sa[0].lcp(sa[0].rk[j] , sa[0].rk[p]) >= i)) p += i ;
if((p - j) / i >= 1)
{
int x = p ;
int lcp1 = 0 ;
if(x < len) lcp1 = sa[0].lcp(sa[0].rk[j] , sa[0].rk[x]) ;
int y = j - 1 ;
int lcp2 = 0 ;
if(y >= 0) lcp2 = sa[1].lcp(sa[1].rk[rev(j - 1)] , sa[1].rk[rev(j + i - 1)]) ;
int res1 = lcp1 + lcp2 + p - j ;
int res2 = i ;
if(1ll * res1 * ans.second > 1ll * res2 * ans.first) ans = {res1 , res2} ;
}
if(p > j) j = p - i ;
}
}
int d = __gcd(ans.first , ans.second) ;
ans.first /= d ;
ans.second /= d ;
cout << ans.first << '/' << ans.second << '\n' ;
return 0 ;
}
温暖的签到题。
#include
using namespace std;
#define M 2005
int a[M];
unordered_mapcnt;
void solve(){
int n;
scanf("%d",&n);
int ans=0;
cnt.clear();
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int j=n;j>=1;j--){
for(int i=j-1;i>=1;i--){
if(cnt.count(2*a[j]-a[i])) ans+=cnt[a[j]+a[j]-a[i]];
}
cnt[a[j]]++;
}
printf("%d\n",ans);
}
int main(){
int T;
scanf("%d",&T);
while(T--)solve();
return 0;
}