题意: 给出A,B ,找出C 使得式子(A^ C)&(B^ C)最小,如果有多个C符合,输出最小的C , 式子最小就是等于0,规律为下表格
A | B | C | ans |
---|---|---|---|
1 | 1 | 1 | 0 |
1 | 0 | 1/0 | 0 |
0 | 1 | 1/0 | 0 |
0 | 0 | 0 | 0 |
中间两行C可以等于1或0,这里选择0 , 那么答案C就是 A&B
#include
#include
#include
using namespace std ;
typedef long long ll ;
const int N=1010 ;
int main(){
int t; scanf("%d",&t) ;
while(t--){
ll a,b; scanf("%lld%lld",&a,&b) ;
ll c=a&b ;
printf ("%lld\n",c?c:1) ;
}
return 0 ;
}
题意:
有一个长度为n的数组,给出m个操作
有两种操作:
题解: 因为本题问的是不属于a[1~r]的数,所以用到权值线段树,线段树 的节点的值转化为数的值,然后询问的时候就是询问[k,n]之间大于r的数
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=1e5+10 ;
const int inf=1e9+7 ;
int a[N],s[N] ; //数组的数 s[i]表示值为i的数最大的下标
struct node{
int l,r ;
int id,v ; //id为节点的值,v为该值的最大下标
}tree[N*4] ;
void push_up(int rt){
if(tree[rt<<1].id>tree[rt<<1|1].id){
tree[rt].id = tree[rt<<1].id ;
tree[rt].v = tree[rt<<1].v ;
}
else{
tree[rt].id = tree[rt<<1|1].id ;
tree[rt].v = tree[rt<<1|1].v ;
}
}
void built(int rt,int l,int r){
tree[rt].l=l , tree[rt].r=r ;
if(l==r){
tree[rt].id=s[l] , tree[rt].v=l ;
return ;
}
int mid=(l+r)>>1 ;
built(rt<<1,l,mid) ;
built(rt<<1|1,mid+1,r) ;
push_up(rt) ;
}
void update(int rt,int idx,int val){
if(tree[rt].l==tree[rt].r) {
tree[rt].id=val ;
return ;
}
int mid=(tree[rt].l+tree[rt].r)>>1 ;
if(idx<=mid) update(rt<<1,idx,val) ;
else update(rt<<1|1,idx,val) ;
push_up(rt) ;
}
int query(int rt,int l,int r,int val){
if(tree[rt].l>r || tree[rt].r<l) return -1 ;
if(tree[rt].l==tree[rt].r){
if(tree[rt].id>val) return tree[rt].v ;
else return -1 ;
}
int ans=-1 ;
if(tree[rt<<1].id>val) ans=query(rt<<1,l,r,val) ;
if(ans==-1&&tree[rt<<1|1].id>val) ans=query(rt<<1|1,l,r,val) ;
return ans ;
}
int main(){
int t; scanf("%d",&t) ;
ll add=10000000 ;
while(t--){
int n,m; scanf("%d%d",&n,&m) ;
// memset(s,0,sizeof(0)) ;
for(int i=1 ; i<=n ; ++i) scanf("%d",&a[i]),s[a[i]]=i ;
built(1,1,n) ;
int ans=0 ;
while(m--){
int x; scanf("%d",&x) ;
if(x==1){
int pos; scanf("%d",&pos) ;
pos = pos^ans ;
update(1,a[pos],inf) ;
}
else{
int r,k ; scanf("%d%d",&r,&k) ;
r=r^ans , k=k^ans ;
if(k>n) ans=k ;
else{
ans = query(1,k,n,r) ; //询问在[k,n]之间大于r的下标
ans = ans==-1?n+1:ans ;
}
printf ("%d\n",ans) ;
}
}
}
return 0 ;
}
#include
using namespace std;
typedef long long ll;
const int N=1e4+10 ;
char g[N][N] ;
int main(){
g[1][1]=g[1][2]=g[2][2]='C' ;
g[2][1]='P';
for(int i=2 ; i<=10; ++i){
int a=1<<(i-2) , b=1<<(i-1), c=1<<i ;
for(int j=1 ; j<=b ; ++j)
for(int k=b+1 ; k<=c ; ++k)
g[j][k] = g[j][k-b] ;
for(int j=b+1 ; j<=c ; ++j)
for(int k=1 ; k<=b ; ++k){
if(g[j-b][k]=='P') g[j][k]='C' ;
else g[j][k]='P' ;
}
for(int j=b+1 ; j<=c ; ++j)
for(int k=b+1 ; k<=c ; ++k)
g[j][k] = g[j-b][k-b] ;
}
int t ; scanf("%d",&t) ;
while(t--){
int k; scanf("%d",&k) ;
int pos=1<<k ;
for(int i=1 ; i<=pos; ++i){
for(int j=1 ; j<=pos ; ++j)
printf ("%c",g[i][j]) ;
printf ("\n") ;
}
}
return 0 ;
}
题意: 1~n张牌按顺序排列,m个操作,每次操作将编号为a的牌抽出来放在最上面,问m轮操作之后牌从上到下的编号。
题意: 记录m个操作,然后从后面放入队列,如果已经放入队列就不用再放,然后按队列弹出,最后没有抽出的牌按顺序输出即可。
#include
#include
using namespace std;
typedef long long ll;
const int N=1e5+10 ;
int n,m ;
bool vis[N] ;
int s[N] ;
int main(){
while(~scanf("%d%d",&n,&m)){
int x ;
queue<int> q ;
for(int i=1 ; i<=n ; ++i) scanf("%d",&x),vis[i]=false ;
for(int i=1 ; i<=m ; ++i) scanf("%d",&s[i]) ;
for(int i=m ; i>0 ; --i)
if(!vis[s[i]]) q.push(s[i]),vis[s[i]]=true ;
while(!q.empty()) printf ("%d ",q.front()),q.pop() ;
for(int i=1 ; i<=n ; ++i)
if(!vis[i]) printf ("%d ",i),vis[i]=true ;
}
return 0 ;
}
题意: 现在有n条鱼,第i条鱼至少需要煮t[i]分钟,每钓一条鱼需要耗费k分钟,钓鱼的时候不能做其他操作,一口锅只能煮一条鱼,问钓完和煮完所有的鱼所耗费的时间。
题解: 在煮第i条鱼的时候,可以再抓t[i]/k条鱼上来,剩下的t[i]%k的时间有两种方案:
#include
#include
#include
using namespace std ;
typedef long long ll ;
const int N=1e5+10 ;
int t[N] ;
priority_queue<int> q ;
bool cmp(int x,int y){
return x>y ;
}
int main(){
int T ; scanf("%d",&T) ;
while(T--){
int n,k ; scanf("%d%d",&n,&k) ;
for(int i=1 ; i<=n ; ++i) scanf("%d",&t[i]) ;
sort(t+1,t+1+n,cmp) ;
while(!q.empty()) q.pop() ;
ll ans=k , pos=1 ;
for(int i=1 ; i<=n ; ++i){
ans += t[i] ;
pos += t[i]/k ;
if(pos<i){
ans += k-q.top() ;
q.pop() ;
}
q.push(t[i]%k) ;
}
printf ("%lld\n",ans) ;
}
return 0 ;
}
题意: 给出一个n个点,m条边带权的有向图,每条路可以无限次走,给出q个询问,每次问第k小的路长是多少(路长走过路的权值之和)。
题解: 可以用优先队列实现,但是由于可能存在菊花图,队列可能会爆和超时,所以先将每个点所连接的边按权值从小到大排列,先所以点最小的边进队(队列存元素path[id-点的id,w该条路径的长度,i该点的第几条变]),然后弹出最小的路径,先有两个操作
#include
#include
#include
#include
using namespace std ;
const int N=5e4+10 ;
struct node{
int to,w ;
node(int a,int b){
to=a,w=b;};
};
struct path{
int id,w,i ; //w为路径的长度,是id的第i条路径
path(int a,int b,int c){
id=a,w=b,i=c;} ;
bool operator < (const path & d) const{
return w>d.w;}
};
vector<node> g[N];
int ans[N] ,query[N];
bool cmp(node x,node y){
return x.w<y.w ;
}
int main(){
int T; scanf("%d",&T) ;
while(T--){
int n,m,q ; scanf("%d%d%d",&n,&m,&q) ;
for(int i=1 ; i<=n ; ++i) g[i].clear() ;
priority_queue<path> que ;
while(m--){
int u,v,w; scanf("%d%d%d",&u,&v,&w) ;
g[u].push_back(node(v,w)) ;
}
for(int i=1 ; i<=n ; ++i){
sort(g[i].begin(),g[i].end(),cmp) ;
if(g[i].size()) que.push(path(i,g[i][0].w,0)) ;
}
int mx=0 ,pos=0 ;
for(int i=0 ; i<q ; ++i){
scanf("%d",&query[i]) ;
mx = max(mx,query[i]) ;
}
while(!que.empty()){
path x=que.top() ; que.pop() ;
ans[pos++]=x.w ;
if(pos>mx) break ;
if(x.i<g[x.id].size()-1)
que.push(path(x.id,x.w-g[x.id][x.i].w+g[x.id][x.i+1].w,x.i+1)) ;
node nx = g[x.id][x.i] ;
if(g[nx.to].size()>0) que.push(path(nx.to,x.w+g[nx.to][0].w,0)) ;
}
for(int i=0 ; i<q ; ++i) printf ("%d\n",ans[query[i]-1]) ;
}
return 0 ;
}