A
搜索即可,每个位置可能的值有2个,然后高位反向递推之后就跟低位一样了。
#include<iostream>
#include<string.h>
#include<algorithm>
#include<string>
#include<set>
#define maxn 30
#define maxh 13
using
namespace
std;
int n;
char s_[maxn];
int s[maxn];
int a[maxn];
int sq[10]={0,1,4,9,6,5,6,9,4,1};
int inv[10]={-1,1,-1,7,-1,-1,-1,3,-1,9};
bool judge(int pos,int b){
if(b==1){
return n==1;
}
if(pos>=2*b-1){
return 2*b-1>=n;
}
if(pos>=b){
int tem=0;
for(int i=pos-b+1;i<b;i++){
tem=(tem+a[i]*a[pos-i]%10)%10;
}
if(tem==s[pos]){
//cout<<"++"<<pos<<endl;
return judge(pos+1,b);
}
else{
//cout<<"--"<<pos<<' '<<tem<<' '<<s[pos]<<endl;
return false;
}
}
else{
int tem=0;
for(int i=1;i<pos;i++){
tem=(tem+a[i]*a[pos-i]%10)%10;
}
for(int i=0;i<10;i++){
if((2*a[0]*i%10+tem)%10==s[pos]){
a[pos]=i;
//cout<<"++"<<pos<<' '<<i<<endl;
if(judge(pos+1,b)) return true;
}
else{
//cout<<"--"<<pos<<' '<<2*a[0]*i%10<<' '<<s[pos]<<endl;
}
}
return false;
}
return false;
}
set<string> sk;
bool check(int b){
bool has=false;
for(int i=0;i<10;i++){
if(sq[i]==s[0]){
a[0]=i;
//cout<<"+"<<a[0]<<endl;
if(judge(1,b)){
string kotae;
for(int j=0;j<b;j++){
kotae+=a[j]+'0';
}
reverse(kotae.begin(),kotae.end());
sk.insert(kotae);
has=true;
}
}
}
return has;
}
signed main(){
scanf("%s",s_);
n=strlen(s_);
for(int i=0;i<n;i++){
s[i]=s_[i]-'0';
}
reverse(s,s+n);
for(int i=1;i<=maxh;i++){
//cout<<"len="<<i<<endl;
if(check(i)){
break;
}
}
if(sk.empty()){
cout<<-1<<endl;
goto end;
}
cout<<*sk.begin()<<endl;
end:
return EOF+1;
}
/*
1208425200945084748250041
*/
B
线段树维护cache的部分,操作1就是区间修改,操作2就是单点查询,维护每一段区间属于哪个数组的什么位置,且版本为多少。
这样得到所有询问对应的数组的版本,然后再顺序扫一遍维护所有数组,碰到查询直接得到答案。
复杂度
O
(
q
l
o
g
n
+
∑
k
)
O(qlogn+\sum k)
O(qlogn+∑k)
#include <iostream>
#include <algorithm>
#define ls (node << 1)
#define rs (node << 1 | 1)
#define mod 256
struct change {
int data, ver, from;
};
const int N = 5e5+7;
struct Node {
int l, r;
bool c;
change val;
}tree[N<<2];
void f(int node, change& k) {
tree[node].val = k;
tree[node].c = 1;
}
void push_down(int node) {
if (tree[node].c) {
f(ls, tree[node].val);
f(rs, tree[node].val);
tree[node].c = 0;
}
}
void build(int node, int L, int R) {
tree[node].l = L, tree[node].r = R;
if (L==R) {
return;
}
int mid = L+R>>1;
build(ls, L, mid);
build(rs, mid+1, R);
}
void modify(int node, int L, int R, change& k) {
if (tree[node].l>=L && tree[node].r<=R) {
f(node, k);
return ;
}
if (tree[node].l>R || tree[node].r<L) return ;
push_down(node);
modify(ls, L, R, k), modify(rs, L, R, k);
}
change query(int node, int x) {
if (tree[node].l==x && tree[node].r==x) return tree[node].val;
push_down(node);
int mid = tree[node].l+tree[node].r>>1;
if (x<=mid) return query(ls, x);
return query(rs, x);
}
struct Node_ {
int l, r, val, add;
Node_() {
l = r = val = add = 0;
}
};
class segTree {
public:
Node_ * tree;
~segTree() {
delete[] tree;
}
void pre(int n, int *nums) {
tree = new Node_[n<<2];
this->build(1, 1, n, nums);
}
void f(int node, int k) {
tree[node].add = (tree[node].add+k)%mod;
tree[node].val = (tree[node].val+k)%mod;
}
void push_down(int node) {
if (tree[node].add) {
this->f(ls, tree[node].add);
this->f(rs, tree[node].add);
tree[node].add = 0;
}
}
void build(int node, int L, int R, int *nums) {
tree[node].l = L, tree[node].r = R;
if (L==R) {
tree[node].val = nums[L];return;
}
int mid = L+R>>1;
this->build(ls, L, mid, nums);
this->build(rs, mid+1, R, nums);
}
void modify(int node, int L, int R, int k) {
if (tree[node].l>=L && tree[node].r<=R) {
this->f(node, k);
return ;
}
if (tree[node].l>R || tree[node].r<L) return ;
this->push_down(node);
this->modify(ls, L, R, k), this->modify(rs, L, R, k);
}
int query(int node, int x) {
if (tree[node].l==x && tree[node].r==x) return tree[node].val;
this->push_down(node);
int mid = tree[node].l+tree[node].r>>1;
if (x<=mid) return this->query(ls, x);
return this->query(rs, x);
}
};
int len[N], nums[N];
segTree alldata[N];
// int cnt[N];
int ans[N], ans_cnt;
struct Q {
int data, ver, pos, i;
bool operator<(const Q& q) const {
return ver<q.ver;
}
} qs[N];
struct OP {
int data, l, r;
}ops[N];
int main() {
int n, m, q;
std::cin >> n >> m >> q;
build(1, 1, n);
for (int i = 1; i<=m; ++i) {
std::cin >> len[i];
for (int j = 1; j<=len[i]; ++j) std::cin >> nums[j];
alldata[i].pre(len[i], nums);
}
int _cnt = 0;
for (int i = 1, &cnt = _cnt, op, x, l, r, p; i<=q; ++i) {
std::cin >> op;
if (op==1) {
std::cin >> x >> p;
change tmp = {x, cnt, p};
modify(1, p, p+len[x]-1, tmp);
} else if (op==2) {
std::cin >> p;
change tmp = query(1, p);
qs[++ans_cnt].data = tmp.data;
qs[ans_cnt].ver = tmp.ver;
qs[ans_cnt].pos = p-tmp.from+1;
qs[ans_cnt].i = ans_cnt;
} else {
std::cin >> x >> l >> r;
ops[++cnt].data = x;
ops[cnt].l = l;
ops[cnt].r = r;
};
}
std::sort(qs+1, qs+1+ans_cnt);
for (int i = 0, t = 1; i<=_cnt && t<=ans_cnt; ++i) {
if (i!=0) {
alldata[ops[i].data].modify(1, ops[i].l, ops[i].r, 1);
}
while (t<=ans_cnt && qs[t].ver<=i) {
// std::cout << qs[t].data << "\n";
if (qs[t].data==0) {
ans[qs[t].i] = 0;
++t;
continue;
}
ans[qs[t].i] = alldata[qs[t].data].query(1, qs[t].pos);
t++;
}
}
for (int i = 1; i<=ans_cnt; ++i) {
std::cout << ans[i] << "\n";
}
return 0;
}
C
数组
a
a
a为初始值,
b
b
b为每一轮的值。
这题如果
a
i
%
b
i
=
0
a_i\%b_i=0
ai%bi=0,则需要
a
i
+
+
a_i++
ai++,而给定的是
b
i
b_i
bi,因此,维护每个数字
k
k
k的倍数在数组
a
a
a中的值,有多个都需要维护,如果重复则只需要1个即可。这样遍历
b
b
b,每次将
m
a
p
[
b
[
i
]
]
map[b[i]]
map[b[i]]中的所有值取出并+1即可,注意这可能需要关联更细其他位置的map。
复杂度
O
(
n
l
o
g
2
n
)
O(nlog^2n)
O(nlog2n)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define mod 1000000007
#define pb push_back
typedef pair<int,int> pir;
string sstr[]={"NO\n","YES\n"};
const int N=300020;
const int maxn=300010;
int T,n,m;
int a[N],b[N],cnt[N];
vector<int> fac[N];
set<int> mul[N];//对于b,存储所有a
signed main()
{
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
cnt[a[i]]++;
}
for(int i=1;i<=m;i++){
cin>>b[i];
}
ll ans=0;
for(int i=1;i<=maxn;i++){
for(int j=i;j<=maxn;j+=i){
fac[j].pb(i);//存储所有因子
}
}
for(int i=1;i<=maxn;i++){
if(cnt[i]){
for(auto j:fac[i]){
mul[j].insert(i);
}
}
}
for(int i=1;i<=m;i++){
int t=b[i];
while(mul[t].size()){//存储了所有t的倍数的a[i],均需要+1
auto tmp=*mul[t].begin();
//cout<<"|||"<<i<<' '<<tmp<<' '<<cnt[tmp]<<'\n';
mul[t].erase(mul[t].begin());
ans+=cnt[tmp];
cnt[tmp+1]+=cnt[tmp];
cnt[tmp]=0;
for(auto j:fac[tmp]){
mul[j].erase(tmp);
}
for(auto j:fac[tmp+1]){//转移到tmp+1
mul[j].insert(tmp+1);
}
}
}
cout<<ans<<'\n';
}
D
将可以一次操作得到的字符串对连边,显然是一个二分图,求二分图的最大独立点集,只需要求最大匹配即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f3f3f3f3f
#define mod 1000000007
#define pb push_back
typedef pair<int,int> pir;
string sstr[]={"No\n","Yes\n"};
const int N=200010;
int n,m,s,t,cnt=1;//从2开始,保证相反边只有低位不同
int to[N],nxt[N],head[N],now[N];//now:当前弧优化
ll wei[N],dis[N],ans,gnum;
void add(int u,int v,ll w)
{
to[++cnt]=v;
wei[cnt]=w;
nxt[cnt]=head[u];
head[u]=cnt;
//反向边
to[++cnt]=u;
wei[cnt]=0;
nxt[cnt]=head[v];
head[v]=cnt;
}
bool bfs()//分层
{
for(int i=0;i<=gnum;i++) dis[i]=inf;
dis[s]=1;now[s]=head[s];
queue<int> q;
q.push(s);
bool flag=0;
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=head[x];i;i=nxt[i]){
int j=to[i];
if(wei[i]&&dis[j]==inf){
q.push(j);
now[j]=head[j];
dis[j]=dis[x]+1;
if(j==t) return 1;
}
}
}
return 0;
}
ll dfs(ll x,ll sum)//当前节点,以及当前节点的总流量
{
if(x==t) return sum;
ll out=0;//out为结果
for(int i=now[x];i&∑i=nxt[i]){
now[x]=i;
int j=to[i];
if(wei[i]>0&&dis[j]==dis[x]+1){
ll k=dfs(j,min(sum,wei[i]));//递归j
if(k==0) dis[j]=inf;//剪枝,去除不可能的点
wei[i]-=k;
wei[i^1]+=k;
out+=k;
sum-=k;
}
}
return out;//总流量
}
vector<int> vec[510];
int len;
string str[510];
map<string,int> mp;
int vis[510];
int c[510];
void dfs(int x)
{
vis[x]=1;
for(auto j:vec[x]){
if(vis[j]) assert(c[x]^c[j]);
else{
c[j]=c[x]^1;
dfs(j);
}
}
return;
}
signed main()
{
cin>>n;
gnum=2*n+2;
s=2*n+1,t=2*n+2;
for(int i=1;i<=n;i++){
cin>>str[i];
mp[str[i]]=i;
}
len=str[1].length();
for(int i=1;i<=n;i++){
for(int j1=0;j1<len;j1++){
for(int j2=j1+1;j2<len;j2++){
string tmp=str[i];
swap(tmp[j1],tmp[j2]);
if(mp.find(tmp)!=mp.end()){
int x=mp[tmp];
if(x>i){
vec[i].pb(x);
vec[x].pb(i);
}
}
}
}
}
int ans=0;
for(int i=1;i<=n;i++){
if(!vis[i]){
dfs(i);
}
}
for(int i=1;i<=n;i++){
for(auto j:vec[i]){
if(c[i]==0&&c[j]==1){
add(i,j,1);
}
}
}
for(int i=1;i<=n;i++){
if(c[i]==0) add(s,i,1);
else add(i,t,1);
}
while(bfs()){
ans+=dfs(s,inf);
}
cout<<n-ans<<'\n';
}
E
主要思想就是贪心+容斥。从前往后贪心当前位置放数字
i
i
i是否可能,利用容斥计算后面的总方案数。由于会溢出导致WA,因此用py。
import math
a=[0 for i in range(52)]
vis=[False for i in range(52)]
def Stagger(n,x):
ans=0
for i in range(0,x+1):
if i%2==0:
ans+=math.comb(x,i)*math.factorial(n-i)
else:
ans-=math.comb(x,i)*math.factorial(n-i)
return ans
def cal_bac(pos,val):
cnt=0
for i in range(pos+1,n+1):
if not vis[i] and i!=val:
cnt+=1
return cnt
def cal_cont(pos,val,x):
x=n-m-pos+x
num=n-pos
bac=cal_bac(pos,val)
if x-n+pos+bac<0 or x-n+pos+bac>bac:
return 0
ans=math.comb(bac,x-n+pos+bac)*Stagger(x,x-n+pos+bac)
return ans
n,m,k=map(int,input().split())
if n==1 and m==1 and k==1:
print(1)
exit()
if m==n-1:
print(-1)
exit()
now=0
stone=0
for pos in range(1,n+1):
for i in range(1,n+1):
if not vis[i]:
if i==pos and stone==m:
continue
cont=cal_cont(pos,i,stone+(i==pos))
if now+cont<k:
now+=cont
else:
a[pos]=i
if i==pos:
stone+=1
vis[i]=True
break
for i in range(1,n+1):
if not vis[i]:
print(-1)
exit()
if now!=k-1:
print(-1)
exit()
for i in range(1,n+1):
print(a[i],end=' ')
F
离散差分。
每个点的贡献是以
a
a
a为中心,附近的
t
/
s
t/s
t/s弧度的范围,特判弧度
>
p
i
>pi
>pi的情形。然后由于是环形的,还需要特判是否经过0,经过的话分成两半即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define mod 1000000007
#define pi 3.1415926535898
#define pb push_back
typedef pair<int,int> pir;
string sstr[]={"NO\n","YES\n"};
const int N=200010;
int T,n,m;
double cur;//斜率
double sum=0;//当前的加速值
map<double,double> mp;//位于每一处,的斜率偏移量;
void add(double t,double s,double a)
{
if(t/s>=pi){//全部覆盖
if(a<pi){
mp[a]-=2*s;
mp[a+pi]+=2*s;
cur+=s;
}
else{
mp[a-pi]+=2*s;
mp[a]-=2*s;
cur-=s;
}
}
else{//部分覆盖
//区间[a-t/s,a]增加,[a,a+t/s]减小
if(a-t/s<0){//分成两半
cur+=s;
mp[a]-=2*s;
mp[a-t/s+2*pi]+=s;
mp[a+t/s]+=s;
}
else if(a+t/s>2*pi){
cur-=s;
mp[a+t/s-2*pi]+=s;
mp[a-t/s]+=s;
mp[a]-=2*s;
}
else{
mp[a]-=2*s;
mp[a-t/s]+=s;
mp[a+t/s]+=s;
}
}
}
signed main()
{
cin>>n;
for(int i=1;i<=n;i++){
double t,s,a;
cin>>t>>s>>a;
add(t,s,a);
sum+=max(0.0,max(t-s*a,t-s*(2*pi-a)));
}
double ans=sum;
double pre=0;
for(auto it:mp){
double tpre=it.first;
double tsub=it.second;
sum+=cur*(tpre-pre);
pre=tpre;
ans=max(ans,sum);
cur+=tsub;
}
printf("%.10lf",ans);
}
G
当前点
u
u
u子树中的任意点
v
v
v,若满足
a
u
<
=
a
v
a_u<=a_v
au<=av,则可以贡献,因此利用dfs序,将子树转化为区间查询,然后将大小关系转化为按照大小来操作线段树即可。注意大小相等应该先更新下面的节点。
线段树区间维护最大值和区间和即可。
#include <iostream>
#include <vector>
#include <algorithm>
#define ls (node << 1)
#define rs (node << 1 | 1)
#define mod 11092019
const int N =1e6+7;
using ll = long long;
// #define int ll
std::vector<int> son[N];
int dep[N], val[N], dfn[N], siz[N], pos[N], cnt;
struct Node {
int l, r, mx;
ll cnt;
Node(): l(0), r(0), mx(0), cnt(0){}
Node operator+(const Node& n) const {
Node res;
res.l = l, res.r = n.r;
if (mx==n.mx) {
res.mx = mx;
res.cnt = (cnt+n.cnt)%mod;
} else if (mx>n.mx) {
res.mx = mx;
res.cnt = cnt;
} else {
res.mx = n.mx;
res.cnt = n.cnt;
}
return res;
}
}tree[N<<2];
void push_up(int node) {
tree[node] = tree[ls]+tree[rs];
}
void build(int node, int L, int R) {
tree[node].l = L, tree[node].r = R;
if (L==R) {
return ;
}
int mid = L+R>>1;
build(ls, L, mid);
build(rs, mid+1, R);
}
void modify(int node, int x, int k, ll _cnt) {
if (tree[node].l==x && tree[node].r==x) {
tree[node].cnt = _cnt;
tree[node].mx = k;
return;
}
if (tree[node].l>x || tree[node].r<x) return;
modify(ls, x, k, _cnt);
modify(rs, x, k, _cnt);
push_up(node);
}
Node query_mx(int node, int L, int R) {
if (tree[node].l>=L && tree[node].r<=R) {
return tree[node];
}
if (tree[node].l>R || tree[node].r<L) return tree[0];
return query_mx(ls, L, R)+query_mx(rs, L, R);
}
void dfs(int node, int depth) {
dep[node] = depth;
dfn[++cnt] = node;
siz[node] = 1;
pos[node] = cnt;
for (int &i:son[node]) {
dfs(i, depth+1);
siz[node]+=siz[i];
}
}
int op[N];
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int n;
std::cin >> n;
for (int i = 1; i<=n; ++i) std::cin >> val[i], op[i] = i;
for (int i = 2, p; i<=n; ++i) {
std::cin >> p;
son[p].push_back(i);
}
dfs(1, 0);
build(1, 1, n);
std::sort(op+1, op+1+n, [&](int x, int y)->bool {
if (val[x]==val[y]) return dep[x]>dep[y];
return val[x]>val[y];
} );
int ans = 0;
ll ans_c = 0;
for (int j = 1; j<=n; ++j) {
int i = op[j];
int l = pos[i]+1, r = pos[i]+siz[i]-1;
int mx_tmp;
ll cnt_tmp;
if (l>r) {
mx_tmp = 1;
cnt_tmp = 1;
} else {
Node tmp = query_mx(1, l, r);
mx_tmp = tmp.mx+1, cnt_tmp = tmp.cnt;
if (mx_tmp==1) cnt_tmp = 1;
}
modify(1, pos[i], mx_tmp, cnt_tmp);
// std::cout << mx_tmp << "---\n";
if (ans<mx_tmp) {
ans = mx_tmp;
ans_c = cnt_tmp;
} else if (ans==mx_tmp) (ans_c+=cnt_tmp)%=mod;
}
std::cout << ans << " " << ans_c;
return 0;
}
H
签到
#include <iostream>
#include <set>
int main() {
std::string s, t;
std::cin >> s >> t;
std::set<std::string> st;
int n = t.size();
for (char &i:t) {
char c = i;
for (char &j:s) {
if (j==c) continue;
i = j;
st.insert(t);
}
i = c;
}
for (int i = 0; i<=n; ++i) {
if (i!=n) st.insert(t.substr(0, i)+t.substr(i+1, n-i-1));
for (char &j:s) {
st.insert(t.substr(0, i)+j+t.substr(i, n-i));
}
}
for (auto &i:st) {
std::cout << i << "\n";
}
return 0;
}
I
搜索带点的连通块数量,并特判样例1那样都被包住但是算1个连通块的数量即可。
#include<iostream>
#define maxn 1003
#define maxm 1003
using
namespace
std;
int n,m;
char s[maxn][maxm];
bool vis[maxn][maxm];
const int dx[8]={1,1,1,0,-1,-1,-1,0};
const int dy[8]={-1,0,1,1,1,0,-1,-1};
int kotae;
bool dfs(int x,int y){
if(x<0||y<0||x==n||y==m) return false;
if(s[x][y]!='.') return true;
if(vis[x][y]) return true;
vis[x][y]=true;
bool ans=true;
for(int i=0;i<8;i++){
if(abs(dx[i])+abs(dy[i])==1){
ans&=dfs(x+dx[i],y+dy[i]);
}
else{
if(x+dx[i]<0||x+dx[i]==n||y+dy[i]<0||y+dy[i]==m) continue;
if(dx[i]^dy[i]){
if(s[x][y+dy[i]]=='/'&&s[x+dx[i]][y]=='/'){
ans&=dfs(x+dx[i],y+dy[i]);
}
}
else{
if(s[x][y+dy[i]]=='\\'&&s[x+dx[i]][y]=='\\'){
ans&=dfs(x+dx[i],y+dy[i]);
}
}
}
}
return ans;
}
signed main(){
scanf("%d %d",&n,&m);
for(int i=0;i<n;i++){
scanf("%s",s[i]);
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(s[i][j]=='.'&&!vis[i][j]){
kotae+=dfs(i,j);
}
}
}
for(int i=0;i<n-1;i++){
for(int j=0;j<m-1;j++){
kotae+=(s[i][j]=='/'&&s[i][j+1]=='\\'&&s[i+1][j]=='\\'&&s[i+1][j+1]=='/');
}
}
printf("%d\n",kotae);
end:
return EOF+1;
}
J
类似单调栈维护即可,若更小则尝试t掉,如果后面该数不出现就不能t
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define mod 1000000007
#define pb push_back
typedef pair<int,int> pir;
string sstr[]={"NO\n","YES\n"};
const int N=200010;
int T,n,k;
int a[N];
int last[N];
int vis[N];
int stkn[N];//数值
int stkp[N];//和位置
int in[N];//标记是否在stk中
int top=-1;
vector<int> ans;
signed main()
{
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=n;i>=1;i--){
if(vis[a[i]]==0){//某个数最后一次出现
last[a[i]]=i;
vis[a[i]]=1;
}
}
memset(vis,0,sizeof(vis));
int p=1,q;
for(int i=1;i<=n;i++){
if(in[a[i]]) continue;//已经在其中
while(top>=0&&i<=last[stkn[top]]&&a[i]<stkn[top]) in[stkn[top]]=0,top--;//后面还有该数字才能t掉
top++;
stkn[top]=a[i];
stkp[top]=i;
in[a[i]]=1;
}
for(int i=0;i<=top;i++) cout<<stkn[i]<<' ';
}
K
unsolved
极角序,每对点
(
i
,
j
)
(i,j)
(i,j)表示当前中心为
i
i
i且转到了
j
j
j,其后继确定,为
(
j
,
k
)
(j,k)
(j,k),这样建图,显然会形成若干环,维护每个环中每个点出现的次数,以及整个环转过的弧度(可能有180,360或者其他)。
因为题目给了一定能转回去,虽然不知道为啥
复杂度
O
(
n
2
l
o
g
n
)
O(n^2logn)
O(n2logn)