sro fjzzq2002
xjb构造三叉树一定有解
时间复杂度 O ( n 2 ) O(n^2) O(n2)
#include
using namespace std;
const int N=5005;
int k,n,a,b,c;
int u[N],v[N],tot,pre;
inline void fd()
{
for(a=1;a<5000;++a)
for(b=a;a+b<5000 && a*b<=k;++b)
if((k-a*b)%(a+b)==0){
if((k-a*b)/(a+b)<=5000-a-b-4)
{c=(k-a*b)/(a+b);
return;}
}
}
int main(){
freopen("diameter.in","r",stdin);
freopen("diameter.out","w",stdout);
int i,j;
scanf("%d",&k);fd();
u[++tot]=(n=1);v[tot]=++n;pre=n;
for(i=1;i<=a;++i){u[++tot]=pre;v[tot]=++n;}
u[++tot]=1;v[tot]=++n;pre=n;
for(i=1;i<=b;++i){u[++tot]=pre;v[tot]=++n;}
if(c){
u[++tot]=1;v[tot]=++n;pre=n;
for(i=1;i<=c;++i) {u[++tot]=pre;v[tot]=++n;}
}
printf("%d\n",n);
for(i=1;i<n;++i) printf("%d %d 1\n",u[i],v[i]);
fclose(stdin);fclose(stdout);
return 0;
}
用你喜爱的数据结构维护:
似乎可以暴力艹标算。
代码咕咕咕。
std:
#include
using namespace std;
const int md = 1e9 + 7;
inline void add(int &x, int y) {
x += y;
if (x >= md) {
x -= md;
}
}
inline void sub(int &x, int y) {
x -= y;
if (x < 0) {
x += md;
}
}
inline int mul(int x, int y) {
return (long long) x * y % md;
}
inline int power(int x, int y) {
int res = 1;
for (; y; y >>= 1, x = mul(x, x)) {
if (y & 1) {
res = mul(res, x);
}
}
return res;
}
template<typename T>
class heap {
private:
priority_queue<T> p, q;
public:
inline void push(T x) {
p.push(x);
}
inline void pop(T x) {
q.push(x);
}
inline void clear() {
while (!p.empty()) {
p.pop();
}
while (!q.empty()) {
q.pop();
}
}
inline bool empty() {
return p.size() == q.size();
}
inline T top() {
while (!q.empty() && p.top() == q.top()) {
p.pop();
q.pop();
}
return p.top();
}
};
#define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
int main() {
FO(price)
ios::sync_with_stdio(false);
cin.tie(0);
int n, m, q;
cin >> n >> m >> q;
unordered_map<int, set<pair<int, int>>> columns;
vector<set<int>> board(n);
int last = 0;
while (q--) {
int type;
cin >> type;
if (type == 1) {
int x, y;
cin >> x >> y;
y = m - y; --x;
if (board[x].count(y)) {
board[x].erase(y);
auto it = columns[y].lower_bound(make_pair(x, 0));
if (it == columns[y].end() || it->first != x) {
--it;
}
int l = it->first, r = it->second;
columns[y].erase(it);
if (l != x) {
columns[y].insert(make_pair(l, x - 1));
}
if (r != x) {
columns[y].insert(make_pair(x + 1, r));
}
} else {
board[x].insert(y);
int l = x, r = x;
{
auto it = columns[y].lower_bound(make_pair(x, x));
while (it != columns[y].end() && it->first == r + 1) {
r = it->second;
columns[y].erase(it++);
}
}
{
auto it = columns[y].lower_bound(make_pair(x, x));
if (it != columns[y].begin()) {
--it;
while (it->second == l - 1) {
l = it->first;
if (it == columns[y].begin()) {
columns[y].erase(it);
break;
}
columns[y].erase(it--);
}
}
}
columns[y].insert(make_pair(l, r));
}
} else {
heap<pair<int, int>> candidates;
set<int> cur;
int ans = 0;
int sum = 0;
for (int i = 0; i < n; ++i) {
int largest = -1;
while (!candidates.empty() && -candidates.top().first == i) {
largest = max(largest, candidates.top().second);
candidates.pop(candidates.top());
}
bool not_found = false;
while (true) {
auto it = board[i].upper_bound(largest);
if (it == board[i].end()) {
not_found = true;
break;
}
while (!cur.empty() && *cur.begin() < *it) {
int x = i, y = *cur.begin();
sub(sum, power(2, y));
cur.erase(y);
--x;
auto it = columns[y].lower_bound(make_pair(x, 0));
if (it == columns[y].end() || it->first != x) {
--it;
}
if (it->second != x) {
candidates.pop(make_pair(-it->second - 1, y));
}
}
if (cur.empty() || *cur.begin() != *it) {
int x = i, y = *it;
add(sum, power(2, y));
cur.insert(y);
auto it = columns[y].lower_bound(make_pair(x, 0));
if (it == columns[y].end() || it->first != x) {
--it;
}
candidates.push(make_pair(-it->second - 1, y));
break;
} else {
largest = *it;
}
}
if (not_found) {
ans = -1;
break;
}
add(ans, sum);
}
cout << ans << "\n";
if (ans != -1) {
last = ans;
}
}
}
return 0;
}
考虑模拟出这个算法进行 k k k轮(即外层的i循环到k)时的序列,之后再暴力模拟零散的步。
打表找规律,观察每个数位置的变化:
1 9 5 4 8 7 2 3 6
1 2 9 5 8 7 4 3 6
1 2 3 9 8 7 5 4 6
1 2 3 4 9 8 7 5 6
1 2 3 4 5 9 8 7 6
1 2 3 4 5 6 9 8 7
1 2 3 4 5 6 7 9 8
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
变化规律(设 v i v_i vi表示数字 i i i位置前面 < i <i <i的数字个数):
前 v i v_i vi轮 i i i位置保持不动,从第 v i + 1 v_i+1 vi+1到第 i − 1 i-1 i−1轮 i i i逐个遍历它后面所有比它小的数的位置,第 i i i轮回归位置 i i i后保持不动。
其实也很好证明:
在第 i i i轮时,维护从位置 i i i开始下表递增的递减序列。
第 i i i轮结束时,数列整体的变换相当于递减序列中所有数在位置上循环右移了一位(末端的 i i i回到了位置 i i i)
而前 v i v_i vi轮 i i i前面都有比它小的数,不可能进入递减序列,所以位置不动。
同时在这 v i v_i vi轮变化中, i i i位置后面的数和 i i i的相对大小保持不变,而 i i i由于前面没有比它小的数所以会一直呆在递减序列中直到回到位置 i i i并在此之前逐个右移遍历后面所有比它小的数的位置。
线段树维护逆序对即可。
a i = n − i + 1 a_i=n-i+1 ai=n−i+1的特判中
j = i + 1 j=i+1 j=i+1写成了 j = i + 2 j=i+2 j=i+2,成功挂掉10分。。。
#include
#include
#include
#include
#include
using namespace std;
const int N=1e6+10;
int n,a[N],m,cnt[35],cot,ans;
int bn[35],mst[35];
char cp,buf[N],wbuf[N],os[100];
int p1,p2,p3;
inline char gc(){
if(p1==p2) p1=0,p2=fread(buf,1,N,stdin);
return p1==p2?EOF:buf[p1++];
}
inline void rd(int &x)
{
cp=getchar();x=0;
for(;!isdigit(cp);cp=getchar());
for(;isdigit(cp);cp=getchar()) x=x*10+(cp^48);
}
inline void wchar(char x)
{
if(p3==N) fwrite(wbuf,1,N,stdout),p3=0;
wbuf[p3++]=x;
}
inline int fd(int x)
{
if(!x) return -1;
int l=0,r=30,mid,y;
for(;l<=r;){mid=(l+r)>>1;(x>=(1<<mid))?(l=(y=mid)+1):(r=mid-1);}
return y;
}
void chg(int x,int y,int op)
{
x=fd(x);if(x==-1) return;
if(op){
if((a[y]>>x)&1) bn[x]++;else{mst[x]++;ans|=(1<<x);}
}else{
if((a[y]>>x)&1) bn[x]--;else{mst[x]--;if((!mst[x])) ans^=(1<<x);}
}
}
inline void prit()
{
int i;
for(i=0;i<=30;++i) if((bn[i] && mst[i])) break;
if(i<=30){
wchar('-');wchar('1');
}
else{
int x=ans,re=0;
for(;(!re)||(x);x/=10) os[++re]='0'+(x%10);
for(;re;--re) wchar(os[re]);
}
if(m>1) wchar('\n');
}
int main(){
freopen("sort.in","r",stdin);
freopen("sort.out","w",stdout);
int i,x,y,l,r,mid;
rd(n);for(i=1;i<=n;++i) rd(a[i]);
for(i=2;i<=n;++i) chg(a[i-1]^a[i],i,1);
rd(m);m++;prit();m--;
for(;m;--m){
rd(x);rd(y);
if(x>1) chg(a[x]^a[x-1],x,0);
if(x<n) chg(a[x]^a[x+1],x+1,0);
a[x]=y;
if(x>1) chg(a[x]^a[x-1],x,1);
if(x<n) chg(a[x]^a[x+1],x+1,1);
prit();
}
if(p3) fwrite(wbuf,1,p3,stdout);
fclose(stdin);fclose(stdout);
return 0;
}
总结
T3还是细节问题,且浪费了很久找了许多无用的性质(没有直接打表)
考试的时候前半段时间安排不紧凑,导致做完T1再肝了T3后T2连暴力都没打。
实际上有几位人赢都T2都暴力艹标算 AC了…十分不划算
所以以后遇到时限5s+的题都可以信仰暴力?