来自队友:题解
/*************
题目:HDU 6702 ^&^
链接:https://vjudge.net/problem/HDU-6702
题意:给一个A,B,输出(A xor C) & (B xor C)值最小的正整数C
类型:思维
思路:输出A&B,如果A&B==0输出1即可
*************/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define met(a,b) memset(a,b,sizeof(a))
#define ios1 ios::sync_with_stdio(false)
#define ios2 cin.tie(0);cout.tie(0)
const int maxn = 1e5+5;
const ll mod = 1e9+7;
const int inf = 0x3f3f3f3f;
int main()
{
int t;scanf("%d",&t);
while(t--){
ll a,b;
scanf("%lld%lld",&a,&b);
if((a&b)==0) printf("1\n");
else printf("%lld\n",a&b);
}
return 0;
}
/*************
题目:HDU 6707 Shuffle Card
链接:https://vjudge.net/problem/HDU-6707
题意:一副牌由n张牌组成。每张卡片都是不同的,编号1到n。起初,牌序为1到n。现在有m次操作,每次抽取一个编号,将该编号的牌放到第一张牌的位置。最后输出所有操作后的卡牌的顺序。
类型:思维
思路:n和m的范围都是1e5,加起来不会爆栈,所以直接拿栈做,然后再用map维护,输出从栈顶往下每个第一次出现的编号。
*************/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define met(a,b) memset(a,b,sizeof(a))
#define ios1 ios::sync_with_stdio(false)
#define ios2 cin.tie(0);cout.tie(0)
const int maxn = 1e5+5;
const ll mod = 1e9+7;
const int inf = 0x3f3f3f3f;
int n,t,m;
int a[maxn],num;
stack<int>sta;
map<int ,int>mp;
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)scanf("%d",&a[i]);
for(int i=n-1;i>=0;i--){sta.push(a[i]);mp[a[i]]++;}
for(int i=0;i<m;i++){
scanf("%d",&num);
sta.push(num);
}
while(!sta.empty()){
int tmp=sta.top();
sta.pop();
if(mp[tmp]){
mp[tmp]--;
printf("%d ",tmp);
}
}
return 0;
}
/*************
题目:HDU 6708 Windows Of CCPC
链接:https://vjudge.net/problem/HDU-6708
题意:递推的模拟,每次左上角,右上角,右下角不变,左下角CCPC取反即可
类型:模拟
思路:模拟
*************/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define met(a,b) memset(a,b,sizeof(a))
#define ios1 ios::sync_with_stdio(false)
#define ios2 cin.tie(0);cout.tie(0)
const int maxn = 1e5+5;
const ll mod = 1e9+7;
const int inf = 0x3f3f3f3f;
struct node{
char a[1500][1500];
}x[15];
int main()
{
ios1;ios2;
int t;cin>>t;
x[1].a[1][1]=x[1].a[1][2]=x[1].a[2][2]='C';
x[1].a[2][1]='P';
for(int i=2;i<=10;i++){
int y=1<<(i-1);
for(int j=1;j<=y;j++){
for(int k=1;k<=y;k++){
x[i].a[j][k]=x[i].a[j][k+y]=x[i].a[j+y][k+y]=x[i-1].a[j][k];
if(x[i-1].a[j][k]=='P') x[i].a[j+y][k]='C';
else x[i].a[j+y][k]='P';
}
}
}
while(t--){
int k;cin>>k;
int n=1<<k;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cout<<x[k].a[i][j];
}
cout<<endl;
}
}
return 0;
}
/*************
题目:HDU 6704 K-th occurrence
链接:https://vjudge.net/problem/HDU-6704
题意:一个字符串,对于每次询问,从l到r的子串在主串中第k次出现的下标是多少,不存在输出-1
类型:后缀数组+ST表+二分+主席树
思路:ST表维护后缀数组排序的ht数组(最长公共长度)的最小值,二分找出左右符合的位置,最后主席树维护后缀数组,求区间第k大
*************/
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
char s[maxn];
int tmp[maxn],rk[maxn],ht[maxn],sa[maxn],str[maxn],st[maxn][22];
int k,n,m;
bool cmp(int i, int j)
{
if(rk[i] != rk[j]) return rk[i] < rk[j];
else {
int ri = i+k<=n? rk[i+k] : -1;
int rj = j+k<=n? rk[j+k] : -1;
return ri<rj;
}
}
void get_sa()
{
for(int i=0;i<=n;i++){
rk[i]=str[i];
sa[i]=i;
}
for(k=1; k<=n; k<<=1){
sort(sa,sa+n,cmp);
tmp[sa[0]] = 0;
for(int i=0;i<n;i++) tmp[sa[i+1]] = tmp[sa[i]] + (cmp(sa[i],sa[i+1])?1:0);
for(int i=0;i<n;i++) rk[i] = tmp[i];
}
for(int i=n;i>0;i--) sa[i] = sa[i-1];sa[0]=n;
int x=0;
for(int i=0;i<=n;i++) rk[sa[i]] = i;
for(int i=0;i<n;i++){
if(x)x--;else x=0;
int j=sa[rk[i]-1];
while(str[i+x] == str[j+x]) x++;
ht[rk[i]] = x;
}
//for(int i=0;i<=n;i++) cout<<"********"<<i<<" "<<sa[i]<<" "<<rk[i]<<" "<<ht[i]<<endl;
}
//st表维护后缀排序后的公共长度的最小值(rmq)
void rmq()
{
for(int i=1;i<=n;i++) st[i][0] = ht[i];
for(int j=1;j<22;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 que_st(int l,int r)
{
int k = (int)(log(r*1.0-l+1)/log(2.0));//int k=log2(r-l+1.0)
return min(st[l][k],st[r-(1<<k)+1][k]);
}
//主席树维护排序后的序列,查询第k大
struct node{
int l,r,val;
}tree[maxn*22];
int root[maxn],tot;
int update(int pre, int l, int r, int pos)
{
int cur = ++tot;
tree[cur] = tree[pre];
tree[cur].val++;
if(l == r) return cur;
int mid = (l+r)>>1;
if(pos <= mid) tree[cur].l = update(tree[pre].l, l, mid, pos);
else tree[cur].r = update(tree[pre].r, mid+1, r, pos);
return cur;
}
int query(int pl, int pr, int l, int r, int k){
if(l == r) return l;
int mid = (l+r)>>1;
if(tree[tree[pr].l].val - tree[tree[pl].l].val >= k) return query(tree[pl].l, tree[pr].l, l, mid, k);
else return query(tree[pl].r, tree[pr].r, mid+1, r, k-(tree[tree[pr].l].val - tree[tree[pl].l].val));
}
int main()
{
int T;scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
scanf("%s",s);
for(int i=0;i<n;i++) str[i] = s[i] - 'a' + 1;
str[n] = 0;
get_sa();
rmq();
tot = 0;
for(int i=1;i<=n;i++){
root[i] = update(root[i-1], 1, n, sa[i]+1);
}
while(m--){
int l,r,k;scanf("%d%d%d",&l,&r,&k);
int len = r-l+1;
l = rk[l-1];
int ll = 1, rr = l, cntl, cntr;
while(ll <= rr){
int mid = (ll+rr)>>1;
int cnt = 100000;
if(mid+1 <= l) cnt = que_st(mid+1,l);
if(cnt >= len) cntl = mid,rr = mid - 1;
else ll = mid + 1;
}
ll = l, rr = n;
while(ll <= rr){
int mid = (ll+rr)>>1;
int cnt = 100000;
if(l+1 <= mid) cnt = que_st(l+1,mid);
if(cnt >= len) cntr = mid, ll = mid +1;
else rr = mid - 1;
}
if(cntr-cntl+1<k) puts("-1");
else printf("%d\n",query(root[cntl - 1], root[cntr], 1, n, k));
}
}
return 0;
}