int prime[maxn+10];
void getprime(){
memset(prime,0,sizeof(prime));
for(int i=2;i<=maxn;i++){
if(!prime[i])prime[++prime[0]]=i;
for(int j=1;j<=prime[0]&&prime[j]<=maxn/i;j++){
prime[prime[j]*i]=1;
if(i%prime[j]==0) break;
}
}
}
复杂度大约是 1 e 4 ∗ l o g ( n ) 1e4*log(n) 1e4∗log(n)
const int maxn = 1e4;
int prime[maxn+10];
void getprime(){
//预处理素数筛
memset(prime,0,sizeof(prime));
for(int i=2;i<=maxn;i++){
if(!prime[i])prime[++prime[0]]=i;
for(int j=1;j<=prime[0]&&prime[j]<=maxn/i;j++){
prime[prime[j]*i]=1;
if(i%prime[j]==0) break;
}
}
}
int find(ll n) //求是否是某个数的三次方
{
int l=maxn;
int r=maxn*100; //x在1e18以内所以最多是1e6的三次方
while(l<=r)
{
int mid=l+r>>1;
ll t=1ll*mid*mid*mid;
if(t<n)
l=mid+1;
if(t>n)
r=mid-1;
if(t==n)
return 1;
}
return 0;
}
int slove(ll n)
{
int ans=64;
for(int i=1;i<=prime[0]&&prime[i]<=n;i++)
{
if(n%prime[i]==0)
{
int t=0;
while(n%prime[i]==0)
{
n/=prime[i];
t++;
}
ans=min(ans,t);
}
}
int u1=sqrt(n);
int u2=sqrt(u1);
if(n==1)
{
return ans;
}
else if(1ll*u2*u2*u2*u2==n)
{
ans=min(ans,4);
return ans;
}
else if(find(n))
{
ans=min(ans,3);
return ans;
}
else if(1ll*u1*u1==n)
{
ans=min(ans,2);
return ans;
}
else
{
return 1;
}
}
ll mod[maxn], y[maxn];
void ex_gcd(ll a, ll b, ll &d, ll &x, ll &y) //d是gcd(a,b)
{
if(!b){
d=a,x=1,y=0;
}else{
ex_gcd(b,a%b,d,y,x);
y-=x*(a/b);
}
}
ll China(int len,ll *a,ll *r){
//a*为模数
ll M=a[1],R=r[1],x,y,d;
for(int i=2;i<=len;i++){
ex_gcd(M,a[i],d,x,y);
if((R-r[i])%d!=0) return -1; //无解
x=(R-r[i])/d*x%a[i];
R-=x*M;
M=M/d*a[i];
R%=M;
}
return (R%M+M)%M; //最小正整数解
}
求解 x 2 ≡ n ( m o d p ) x^2\equiv n(mod p) x2≡n(modp),复杂度只有求快速幂的log。
当且仅当模数为奇素数时可用
ll mod = 1e9 + 7;
ll w, n;
struct Complex //复数
{
ll x, y;
Complex(ll _x = 0, ll _y = 0)
{
x = _x;
y = _y;
}
};
Complex operator*(Complex a, Complex b) //复数乘
{
return Complex((a.x * b.x % mod + a.y * b.y % mod * w % mod) % mod, (a.x * b.y + a.y * b.x) % mod);
}
ll qpow(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
ans = ans * x % mod;
x = x * x % mod;
y >>= 1;
}
return ans;
}
Complex qpow(Complex a, ll y)
{
Complex ans = Complex(1, 0);
while (y)
{
if (y & 1)
ans = ans * a;
a = a * a;
y >>= 1;
}
return ans;
}
ll Legendre(ll x,ll mod)
{
return qpow(x, (mod - 1) >> 1);
}
int slove(ll n,ll mod) //返回值为其中一个解,另一个解为mod-返回值
{
if(n==0)
return 0;
if(n==1)
return 1;
if(Legendre(n,mod)+1==mod)
return -1; //非二次剩余,在mod下无法开方
ll a, temp;
while(1)
{
a = rand() % mod;
temp=a*a-n;
w=(temp%mod+mod)%mod;
if(Legendre(w,mod)+1==mod) break;
}
Complex te;
te.x=a;
te.y=1;
Complex ans=qpow(te,(mod+1)>>1);
return ans.x;
}
const int MAXN=100005;
int n,m;
vector<int> g[MAXN];
int dfn[MAXN],low[MAXN],cnt=0,index=0;
int scc[MAXN],size[MAXN];
bool inStack[MAXN];
stack<int> st;
void tarjan(int u)
{
index++;
dfn[u]=index;
low[u]=index;
st.push(u);
inStack[u]=true;
for(int i=0;i<g[u].size();i++)
{
if(!dfn[g[u][i]])
{
tarjan(g[u][i]);
low[u]=min(low[u],low[g[u][i]]);
}
else if(inStack[g[u][i]])
low[u]=min(low[u],dfn[[u][i]]);
}
if(low[u]==dfn[u])
{
cnt++;
int t;
do
{
t=st.top();
scc[t]=cnt; //缩点后的新编号
size[cnt]++; //缩点后点集数量
inStack[t]=false;
st.pop();
}while(t!=u);
}
}
缩点后重新构图
//g是原图,G是缩点后的新图
//have_edge 防止重边
int have_edge[maxn][maxn];
for(int i=1;i<=n;i++)
{
for(int j=0;j<g[i].size();j++)
{
if(scc[i]!=scc[g[i][j]] && !have_edge[scc[i]][scc[g[i][j]]])
{
have_edge[scc[i]][scc[g[i][j]]]=1;
G[scc[i]].push_back(scc[g[i][j]]);
}
}
}
void tarjan(int x){
dfn[x]=low[x]=cnt++;
int son=0;
for(int i=0;i<g[x].size();i++){
int v=g[x][i];
if(!dfn[v]){
son++;
tarjan(v);
low[x]=min(low[x],low[v]);
if(low[v]>=dfn[x] && dfn[x]!=1) ans.insert(x);
else if(x==1 && son>1){
ans.insert(x);
}
}
else{
low[x]=min(low[x],dfn[v]);
}
}
}
每次只能合并L-R堆。复杂度 O ( n 4 ) O(n^4) O(n4)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define INF 0x3f3f3f3f
#define INFLL 0x3f3f3f3f3f3f3f3f
#define FIN freopen("input.txt","r",stdin);
#define mem(x,y) memset(x,y,sizeof(x));
int sum[205];
int dp[105][105][105];
int n,l,r;
void init()
{
sum[0]=0;
memset(dp,INF,sizeof(dp));
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
dp[i][j][j-i+1]=0;
}
}
}
int main() {
while(cin>>n>>l>>r)
{
init();
for(int i=1;i<=n;i++)
{
scanf("%d",&sum[i]);
sum[i]=sum[i]+sum[i-1];
}
for(int len=2;len<=n;len++)
{
for(int i=1;i<=n;i++)
{
int j=i+len-1;
if(j>n)
break;
for(int k=len;k>=1;k--)
{
if(k==1)
{
for(int s=l;s<=r;s++)
{
dp[i][j][k]=min(dp[i][j][k],dp[i][j][s]+sum[j]-sum[i-1]);
}
}
else
{
for (int x=i;x<j;x++)
{
dp[i][j][k]=min(dp[i][j][k],dp[i][x][k]+dp[x+1][j][k-1]);
}
}
}
}
}
if(dp[1][n][1]==INF)
{
printf("0\n");
}
else
printf("%d\n",dp[1][n][1]);
}
}
#define lson node<<1
#define rson node<<1|1
ll tree[4*maxn]; // 线段树
ll a[maxn];
void init(){
memset(tree,0,sizeof(tree));
}
// 创建线段树
void build(int node,int l,int r){
if(l == r){
tree[node]=a[l];
return;
}
int mid = (l+r)/2;
build(lson,l,mid);
build(rson,mid+1,r);
tree[node] = tree[lson] + tree[rson];
}
// 单点更新,add为更新值,index为更新点
void update(int node,int l,int r,int index,int add){
if(l == r) {
tree[node] = add; // 更新方式,可以自由改动
return;
}
int mid = (l+r) / 2;
if(index <= mid){
update(lson,l,mid,index,add);
}else{
update(rson,mid+1,r,index,add);
}
tree[node] = tree[lson] + tree[rson];
}
// 区间查找
ll query(int node,int l,int r,int L,int R){
if(l >= L && r <= R) return tree[node];
int mid = (l+r) / 2;
ll sum = 0;
if(mid >= L) sum += query(lson,l,mid,L,R);
if(mid < R) sum += query(rson,mid+1,r,L,R);
return sum;
}
#define lson node<<1
#define rson node<<1|1
ll tree[4*maxn]; // 线段树
ll lz[4*maxn]; // 延迟标记
ll a[maxn];
void init(){
memset(tree,0,sizeof(tree));
memset(lz,0,sizeof(lz));
}
// 创建线段树
void build(int node,int l,int r){
if(l == r){
tree[node]=a[l];
return;
}
int mid = (l+r)/2;
build(lson,l,mid);
build(rson,mid+1,r);
tree[node] = tree[lson] + tree[rson];
}
void push_down(int node,int l,int r){
if(lz[node]){
//这里根据实际操作进行修改
int mid = (l+r) / 2;
lz[lson] += lz[node];
lz[rson] += lz[node];
tree[lson] += 1LL*(mid - l + 1)*lz[node];
tree[rson] += 1LL*(r - mid)*lz[node];
lz[node] = 0;
}
}
// 区间更新,lr为线段树范围,LR为更新范围,add为更新值
void update(int node,int l,int r,int L,int R,int add){
if(l >= L && r <= R){
lz[node] += 1LL*add;
tree[node] += 1LL*(r - l + 1)*add; // 更新方式
return;
}
push_down(node,l,r);
int mid = (l+r) / 2;
if(mid >= L) update(lson,l,mid,L,R,add);
if(mid < R) update(rson,mid+1,r,L,R,add);
tree[node] = tree[lson] + tree[rson];
}
// 区间查找
ll query(int node,int l,int r,int L,int R){
if(l >= L && r <= R) return tree[node];
push_down(node,l,r);
int mid = (l+r) / 2;
ll sum = 0;
if(mid >= L) sum += query(lson,l,mid,L,R);
if(mid < R) sum += query(rson,mid+1,r,L,R);
return sum;
}
#define mid (l+r)/2
#define maxn 1000007 //元素个数
ll n,m;
ll rt=1,cnt=1;
ll lson[maxn*40],rson[maxn*40];
ll Lazy[maxn*40];//区间增加的lazy标记
ll sum[maxn*40];//线段树求和最多分成4个子区间
void init()
{
for(int i=0;i<=cnt;i++)
{
sum[i]=0;
Lazy[i]=0;
}
rt=cnt=1;
}
ll Get_Son(long long &pos)
{
if(pos==0) pos=++cnt;
return pos;
}
void PushUp(long long pos)
{
sum[pos]=sum[lson[pos]]+sum[rson[pos]];
}
void PushDown(long long pos,long long l,long long r)//区间查询用
{
//l,r为左子树,右子树的数字区间
// if(Lazy[pos]==0) return;
// if(r-l<=1) return;
// if(pos<<1!=0)
// {
// pos<<1=++cnt;
// sum[pos<<1]+=(mid-l+1)*Lazy[pos];
// Lazy[pos<<1]+=Lazy[pos];
// }
// if(rson[pos]!=0)
// {
// rson[pos]=++cnt;
// sum[rson[pos]]+=(r-mid+1)*Lazy[pos];
// Lazy[rson[pos]]+=Lazy[pos];
// }
sum[Get_Son(lson[pos])]+=(mid-l+1)*Lazy[pos];
sum[Get_Son(rson[pos])]+=(r-mid)*Lazy[pos];
Lazy[lson[pos]]+=Lazy[pos];
Lazy[rson[pos]]+=Lazy[pos];
Lazy[pos]=0;
}
void Update(long long &pos,long long l,long long r,long long L,long long R,long long C)
{
//L,R表示操作区间 , l,r表示当前节点区间 , pos表示当前节点编号
if(pos==0) pos=++cnt;
if(Lazy[pos]!=0) PushDown(pos,l,r);//下推标记
if(L<=l && R>=r)//节点区间在操作区间之内,直接返回
{
sum[pos]+=(r-l+1)*C;//这个点需要加上区间长度*C
Lazy[pos]+=C;//用Lazy标记,表示本区间的Sum正确,子区间的Sum仍需要根据Lazy调整
return;
}
if(L<=mid) Update(lson[pos],l,mid,L,R,C);
if(R>mid) Update(rson[pos],mid+1,r,L,R,C);
PushUp(pos);
}
ll Query(long long pos,long long l,long long r,long long ql,long long qr)
{
//L,R表示操作区间 , l,r表示当前节点区间 , pos表示当前节点编号
if(pos==0) return 0;
if(Lazy[pos]) PushDown(pos,l,r);//下推标记,否则sum可能不正确
if(ql<=l && qr>=r)//节点区间在操作区间之内,直接返回
{
return sum[pos];
}
//统计答案
long long ans=0;
if(ql<=mid) ans+=Query(lson[pos],l,mid,ql,qr);
if(qr>mid) ans+=Query(rson[pos],mid+1,r,ql,qr);
PushUp(pos);
return ans;
}
#include
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 20;
int lson[maxn*30],rson[maxn*30],tree[maxn*30];
int a[maxn],ha[maxn],T[maxn];
int n,m,len,tot;
void init_hash()
{
sort(ha + 1, ha + 1 + n);
len = unique(ha + 1, ha + 1 + n) - ha - 1;
for (int i = 1; i <= n;i++)
{
a[i] = lower_bound(ha + 1, ha + 1 + len,a[i]) - ha;
}
}
void init()
{
tot=0;
init_hash();
}
int build(int l,int r)
{
int rt = tot++;
tree[rt] = 0;
if (l!=r)
{
int mid = (l + r) >> 1;
lson[rt] = build(l, mid);
rson[rt] = build(mid + 1, r);
}
return rt;
}
int update(int rt,int pos,int val)
{
int newroot = tot++;
int temp = newroot;
tree[newroot] = tree[rt] + val; //更新区间和
int l = 1, r = len;
while (l<r) //这里迭代更新比递归快一点
{
int mid = (l + r) >> 1;
if (pos<=mid)
{
lson[newroot] = tot++;
rson[newroot] = rson[rt];
newroot = lson[newroot];
rt = lson[rt];
r = mid;
}
else
{
rson[newroot] = tot++;
lson[newroot] = lson[rt];
newroot = rson[newroot];
rt = rson[rt];
l = mid + 1;
}
tree[newroot] = tree[rt] + val;
}
return temp;
}
int query(int st,int end,int k)
{
int l = 1, r = len;
while(l<r){
int mid = (l + r) >> 1;
if (tree[lson[end]]-tree[lson[st]]>=k)
{
r = mid;
st = lson[st];
end = lson[end];
}
else
{
l = mid + 1;
k -= tree[lson[end]] - tree[lson[st]];
st = rson[st];
end = rson[end];
}
}
return l;
}
int main(){
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
ha[i] = a[i];
}
init();
T[0] = build(1, len);
for (int i = 1; i <= n;i++)
{
T[i] = update(T[i - 1], a[i], 1);
}
for (int i = 1; i <= m;i++)
{
int l, r,k;
scanf("%d%d%d", &l, &r, &k);
int ans = ha[query(T[l - 1], T[r], k)];
printf("%d\n", ans);
}
}
n*m的数码问题有一个结论:
1.假如m是奇数,那么上下交换会改变(m-1)也就是偶数次逆序数,左右交换(空格和左右交换)不改变逆序数,因此逆序数的奇偶性不变,此时两状态的奇偶性一致即有解
2.假如m是偶数,上下交换会改变奇数次逆序数,左右交换不改变逆序数,因此逆序数奇偶性会因上下交换而改变,此时逆序数之差和两个局面下空格所在行数之差
的奇偶性相同即有解。
但是,这里所指的逆序数是不计算0的,或者是把0变为16再计算!!!!
也就是除空格外,剩下数的逆序数之差才是我们要求的东西
ll inverse(ll a)
{
return a == 1 ? 1 : 1LL * (mod - mod / a) * inverse(mod % a) % mod;
}
inline bool read(T &ret) {
char c; int sgn;
if(c=getchar(),c==EOF) return 0; //EOF
while(c!=' '&&(c<'0'||c>'9')) c=getchar();
sgn=(c==' ')? 1:1;
ret=(c==' ')?0:(c-'0');
while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
ret*=sgn;
return 1;
}
mt19937_64 gen(time(0));
int main()
{
srand(time(0));
int a=gen()%10; //貌似c++14才能用
}
int digitCounts(int k, int n) {
// write your code here
int count = 0 , x;
if (k == 0 && n == 0) count = 1;
for (int i = 1;x = n / i;i *= 10) {
int high = x / 10;
if (k == 0) {
if (high) high--;
else {
count++;
break;
}
}
count += high * i;
int current = x % 10;
if (current > k) count += i;
else if (current == k) count += n - x * i + 1;
}
return count;
}
复杂度大约是 O ( n l o g n ) O(nlogn) O(nlogn)
使用方式就是,把数存进a数组,然后调用mergesort( l, r),sum就是所求值
int a[maxn],temp[maxn];
long long sum=0;
void merge(int l,int r,int m){
int i = l, j = m + 1,k = l;
while(i<=m&&j<=r){
if(a[i] > a[j]){
sum += m - i + 1;
temp[k++] = a[j++];
}else{
temp[k++] = a[i++];
}
}
while(i<=m)
temp[k++] = a[i++];
while(j<=r)
temp[k++] = a[j++];
for(i = l;i<=r;i++)
a[i] = temp[i];
}
void mergesort(int l,int r){
if(l<r){
int m = (l + r) / 2;
mergesort(l,m);
mergesort(m+1,r);
merge(l,r,m);
}
}