#include
#define ll long long
#define lowbit(x) ((x)&(-(x)))
using namespace std;
int main()
{
int T;cin>>T;
ll a,b,c;
while(T--){
scanf("%lld%lld", &a, &b);
c = 0;
ll k = 1;
int last = 0;
for(int i = 32; i >= 0; --i){
ll ba = (a&(k<<i)), bb = (b&(k<<i));
if(ba && bb){
c |= (k<<i);
}
else if(ba^bb) last = i;
}
if(c == 0) c = 1<<last;
cout<<c<<endl;
}
}
1002: array
做法1:
在[1,r]找没出现的,相当于在[r+1,end]找出现过的,在最后一个位置加一个n+1。用主席树找[r+1,end]出现的最小的大于等于k的数字。每个操作一可以看成在end位置添加一个a[pos]。
#include
#define ll long long
#define lowbit(x) ((x)&(-(x)))
#define mid ((l+r)>>1)
using namespace std;
const int maxn = 2e5 + 50;
int sz[maxn*20], lc[maxn*20], rc[maxn*20];
int T[maxn];
int a[maxn];
int n, m;
int tot;
void build(int pre, int &cur, int l, int r, int pos){
cur = ++tot;
sz[cur] = sz[pre]+1;
lc[cur] = lc[pre]; rc[cur] = rc[pre];
if(l == r) return;
if(pos <= mid)
build(lc[pre], lc[cur], l, mid, pos);
else
build(rc[pre], rc[cur], mid+1, r, pos);
}
int qry(int pre, int cur, int l, int r, int k)
{
if(sz[cur] - sz[pre] == 0) return -1;
if(l == r){
return l;
}
int res = -1;
if(k <= mid)
res = qry(lc[pre], lc[cur], l, mid, k);
if(res == -1)
res = qry(rc[pre], rc[cur], mid+1, r, k);
return res;
}
int main()
{
int ca;scanf("%d", &ca);
while(ca--){
tot = 0;
scanf("%d%d", &n, &m);
int ans = 0;
for(int i = 1; i <= n; ++i){
scanf("%d", &a[i]);
build(T[i-1], T[i], 1, n+1, a[i]);
}
int p = n+1;
build(T[n], T[p], 1, n+1, n+1);
while(m--){
int op; scanf("%d", &op);
if(op == 1){
int pos; scanf("%d", &pos);
pos = pos^ans;
if(a[pos] == -1) continue;
build(T[p], T[p+1], 1, n+1, a[pos]);
p++;
a[pos] = -1;
}
else{
int r, k;
scanf("%d%d", &r, &k);
r ^= ans; k ^= ans;
ans = qry(T[r], T[p], 1, n+1, k);
printf("%d\n", ans);
}
}
}
}
做法2:
线段树维护每个值出现的下标,查询的时候相当于找[k,n]中第一个出现的下标值大于等于r的值。操作一相当于使得相应的值下标值变为inf。
做法3:
先预处理出没有进行操作1的答案,然后用set维护每次操作1删除的数字,查询的时候就是min(ans[r],*lower_bound(k))
1003:array
后缀自动机fail树上dfs序建可持久化线段树(据说是人尽皆知傻逼题,不会写的我瑟瑟发抖
1004: path
类似最短路的思路,一开始先把所有的边放进set,然后每次弹出一个最短的路径去更新,如果当前set的size比max(k)还要大,那么看更新的路径是否比set中最长的还要长,如果是,那么就停止更新,否则把那条最长的路径删了,把当前更新的路径加进去。
#include
#define ll long long
#define lowbit(x) ((x)&(-(x)))
#define P pair
using namespace std;
const int maxn = 5e4 + 50;
vector<P> g[maxn];
vector<int> Q;
vector<ll> ans;
int n, m, t;
int mx;
struct node{
ll dis;
int v, id;
node(ll _dis = 0, int _v = 0, int _id = 0) : dis(_dis), v(_v), id(_id){
}
bool operator < (const node& a)const{
if(dis != a.dis) return dis < a.dis;
else return id < a.id;
}
};
int tot = 0;
set<node> s;
void init(){
scanf("%d%d%d", &n, &m, &t);
s.clear();
ans.clear();
Q.clear();
for(int i = 1; i <= n; ++i) g[i].clear();
mx = 0; tot = 0;
while(m--){
int u, v; ll w;
scanf("%d%d%lld", &u, &v, &w);
g[u].push_back(P(w, v));
s.insert(node(w, v, ++tot));
}
for(int i = 1; i <= n; ++i) sort(g[i].begin(), g[i].end());
for(int i = 0; i < t; ++i){
int k; scanf("%d", &k);
Q.push_back(k);
mx = max(mx, k);
}
}
void sol()
{
for(int i = 0; i < mx; ++i){
node temp = *s.begin();
s.erase(*s.begin());
ans.push_back(temp.dis);
if(i == mx-1) break;
int u = temp.v;
ll dis = temp.dis;
for(int j = 0; j < g[u].size(); ++j){
ll w = g[u][j].first;
int v = g[u][j].second;
if(i + s.size() > mx){
set<node>::iterator it = --s.end();
if(dis + w >= (*it).dis) break;
s.erase(it);
s.insert(node(dis+w, v, ++tot));
}
else{
s.insert(node(dis+w, v, ++tot));
}
}
}
for(int i = 0; i < Q.size(); ++i){
int k = Q[i];
printf("%lld\n", ans[k-1]);
}
}
int main()
{
int T;cin>>T;
while(T--){
init();sol();
}
}
1006:Shuffle Card
倒着写,最后一次出现的数字一定在第一个,然后依次放,如果出现过就不管他。处理完之后看按剩下的数字原本的顺序放。
1007:Windows Of CCPC
按题意模拟。
#include
#define ll long long
#define lowbit(x) ((x)&(-(x)))
using namespace std;
int a[1<<11][1<<11];
void sol(int k)
{
int len = 1<<k;
for(int i = 0; i < len; ++i){
for(int j = 0; j < len; ++j){
if(a[i][j] == 0) printf("C");
else printf("P");
}printf("\n");
}
}
int main()
{
a[0][0] = a[0][1] = 0;
a[1][0] = 1; a[1][1] = 0;
for(int i = 2; i <= 10; ++i){
int len = (1<<(i-1));
for(int x = 0; x < len; ++x){
for(int y = 0; y < len; ++y){
a[x][y+len] = a[x+len][y+len] = a[x][y];
a[x+len][y] = a[x][y]^1;
}
}
}
int T;cin>>T;
while(T--){
int k;
cin>>k;
sol(k);
}
}
1008:Fishing Master
抓第一条鱼的花费k和煮鱼的总时间是一定要花费的。然后你可以在煮鱼的时候去钓鱼,那么额外时间就出现在你去钓鱼的途中鱼已经煮好了,但是你得钓完鱼才能继续煮鱼。所以如果你可以在煮鱼的时间内把n-1条鱼都钓走,那么就可以没有额外花费,否则就按照煮鱼时间对k的模数从大到小选择额外间隔时间,额外时间是(k-mod),mod是t对k的模数。
#include
#define ll long long
#define lowbit(x) ((x)&(-(x)))
using namespace std;
const int maxn = 1e5 + 50;
ll t[maxn];
ll m[maxn];
ll k;
int n;
int main()
{
int T;cin>>T;
while(T--){
scanf("%d%lld", &n, &k);
ll num = 0, ans = k;
for(int i = 0; i < n; ++i) {
scanf("%d", &t[i]);
m[i] = t[i]%k;
num += t[i]/k;
ans += t[i];
}
if(num >= n-1){
cout<<ans<<endl;
}
else{
sort(m, m+n);
for(int i = 0; i < n-1-num; ++i){
ans += (k-m[n-1-i]);
}
cout<<ans<<endl;
}
}
}