傳送門ios
題意:
給出一張無向圖,如今問最少多少次「一筆畫」可以覆蓋全部的邊,而且輸出方案數。c++
思路:算法
尚未寫代碼,就貼貼標程吧,兩次dfs,第一次搜出連通塊而且找到奇數點,第二次就執行相似於上述的算法。
ui
#include<bits/stdc++.h> using namespace std; int n,m,w[100010],a[100010],b[300010],c[300010],d[300010],r=1,p; vector<int> f,x[100010]; bool u[100010]; inline void add_(int i,int j) { w[i]++; b[++r]=j; c[r]=a[i]; a[i]=r; } inline void add(int i,int j) { add_(i,j); add_(j,i); } inline void dfs(int i) { int j; u[i]=1; if(w[i]&1) f.push_back(i); for(j=a[i];j;j=c[j]) if(!u[b[j]]) dfs(b[j]); } inline void dfs2(int i) { int j; for(j=a[i];j;j=c[j]) if(!d[j]) { d[j]=d[j^1]=1; dfs2(b[j]); if(j>2*m+1) p++; else x[p].push_back(j/2*(2*(j&1)-1)); } } int main() { int i,j,k; while(scanf("%d%d",&n,&m)!=EOF) { for(i=1;i<=m;i++) { scanf("%d%d",&j,&k); add(j,k); } for(i=1;i<=n;i++) if(!u[i] && w[i]) { dfs(i); if(!f.size()) { f.push_back(i); f.push_back(i); } for(j=2;j<f.size();j+=2) add(f[j],f[j+1]); p++; dfs2(f[0]); f.clear(); } printf("%d\n",p); for(i=1;i<=p;i++) { printf("%d ",x[i].size()); for(j=0;j<x[i].size();j++) printf("%d ",x[i][j]); printf("\n"); x[i].clear(); } for(i=1;i<=n;i++) a[i]=w[i]=u[i]=0; for(i=1;i<=r;i++) d[i]=0; p=0; r=1; } return 0; }
輸出"YES"便可。spa
題意:
構造\(01\)長寬都爲\(n,n\leq 2000\)的矩陣,保證矩陣中不存在四個角都爲\(1\)的矩形,而且\(1\)的個數很多於\(85000\)。.net
思路:
構造十分神奇,我是想不出來的QAQ。
首先對矩陣分塊,咱們取一個素數\(p=47\),其實就至關於\(\sqrt{n}\)的樣子,那麼如今就有\(p*p\)個小矩形,每一個矩形大小爲\(p*p\)。
若每行每列都只放一個,也就是每一個小矩形就放\(p\)個\(1\),那麼最終的答案就有\(p^3\)個\(1\),也差很少就是\(85000\)了。
而後構造的時候就循環放置,只保證存在一列有重複,其餘列都各不重複,能夠證實當\(p\)爲素數時是存在方案的(這也就是爲啥選素數的緣由)。
好比對於\(p=5\)的狀況,咱們就相似於這樣構造:code
10000 10000 10000 10000 10000 10000 01000 00100 00010 00001 10000 00100 00001 01000 00010 10000 00010 01000 00001 00100 10000 00001 00010 00100 01000 01000 ... 01000 ... ...
能夠證實,這樣放置確定不會存在重複,最終找到規律,只須要讓\(a[kp+b][ip+(ki+b)\% p]=1\)便可。
證實挺好證的,構造四個點而後列等式便可,發現只有當\(p\)爲質數時纔不矛盾(可是一開始怎麼想獲得這是素數...)ip
這個題大概就這麼作...我感受想到素數分塊這一步很難,多是我積累少了吧...ci
upd:剛纔發現這個可能和徹底剩餘繫有關,設\(\{a_k\}\)爲模\(p\)的徹底剩餘系,那麼對於任意\(gcd(p,x)=1\)的\(x\),都有\(\{xa_k\}\)爲另外一個徹底剩餘系,而且知足題中條件。
證實以下:
假設如今有\(x*a_i\equiv x*a_j\),那麼即有\(x*(a_i-a_j)\equiv 0\),由於\(gcd(x,p)=1\),那麼就有\(a_i\equiv a_j\)。也就是說當\(a_j\not ={a_i}\)時,有\(xa_j\not ={xa_i}\)。
那麼咱們能夠將\(p\)行爲一塊獨立來看,除開全部都相同的那一列,其他的列都構成多個徹底剩餘系,也就是不會出現重複的。
多個塊之間由於最多加\(p-1\),因此也不會出現重複。get
感性證實就完成啦(爲啥感受寫了一萬年)
題意:
給出兩個序列\(a,b\),一開始\(a\)全爲\(0\),\(b\)爲一個排列。而後有兩個操做:
思路:
線段樹維護兩個值便可,一個爲答案,另外一個爲還剩多少就會\(+1\)的最小值。若是當前要\(+1\),線段樹暴力更新便可。
能夠知道\(+1\)不會超過\(\sum_{i=1}^n\lfloor\frac{n}{b_i}\rfloor=O(logn)\)次,因此複雜度大概\(O(nlog^2n)\)的樣子。
#include<bits/stdc++.h> typedef long long ll; typedef unsigned long long ull; typedef double db; const int MAXN = 1e5+5,MAXM = 4e5+5,MOD = 100003,INF = 0x3f3f3f3f; const ll INFL = 0x3f3f3f3f3f3f3f3f; const db eps = 1e-9; #define lson o<<1,l,m #define rson o<<1|1,m+1,r #define mid l + ((r-l)>>1) #define rep(i,a,b) for(register int i=(a);i<=(b);i++) #define pii pair<int,int> #define vii vector<pii> #define vi vector<int> using namespace std; int n,q,b[MAXN],dif[MAXN<<2],mv[MAXN<<2]; ll sumv[MAXN<<2]; inline void pushUp(int o){ dif[o]=min(dif[o<<1],dif[o<<1|1]); sumv[o]=sumv[o<<1] + sumv[o<<1|1]; } void build(int o,int l,int r){ mv[o]=0; if(l==r){ dif[o] = b[l]; sumv[o]=mv[o]=0; return ; } int m=mid; build(lson);build(rson); pushUp(o); } inline void pushDown(int o){ if(mv[o]){ mv[o<<1] += mv[o]; mv[o<<1|1] += mv[o]; dif[o<<1] -=mv[o]; dif[o<<1|1]-=mv[o]; assert(dif[o<<1]>=0); assert(dif[o<<1|1]>=0); mv[o]=0; } } void update2(int o,int l,int r){ if(l==r){ dif[o] = b[l];mv[o]=0; sumv[o]++; return ; } int m=mid; pushDown(o); if(dif[o<<1]==0)update2(lson); if(dif[o<<1|1]==0)update2(rson); pushUp(o); } void update(int o,int l,int r,int L,int R){ if(l>=L&&r<=R){ dif[o]--;mv[o]++; if(dif[o]==0)update2(o,l,r); return ; } int m=mid; pushDown(o); if(L<=m)update(lson,L,R); if(R>m)update(rson,L,R); pushUp(o); } ll query(int o,int l,int r,int L,int R){ if(dif[o]==0)update2(o,l,r); if(l>=L&&r<=R){ return sumv[o]; } int m=mid; ll ans=0; pushDown(o); if(L<=m)ans+=query(lson,L,R); if(R>m)ans+=query(rson,L,R); return ans; } int main(){ ios::sync_with_stdio(false); while(cin>>n>>q){ for(int i=1;i<=n;i++)cin>>b[i]; build(1,1,n); while(q--){ static char op[7]; static int l,r; cin>>op>>l>>r; if(op[0]=='a')update(1,1,n,l,r); else cout<<query(1,1,n,l,r)<<'\n'; } } return 0; }
求逆序對個數便可。