NOIP2017提高組 模擬賽 26(總結)

2021-08-09 07:40:34 字數 4344 閱讀 8476

【題目描述】

【解題思路】

①構造法:

假設現在有m個點,刪除乙個點,剩下的m-1個點都已經確定,那麼刪除的這個點應該染什麼顏色。

假如這個點所在的行的點數為奇數,那麼點的染色只與它所在的列有關(若列有偶數個點,那麼這個點的顏色就可以確定了,哪種顏色少選哪種。否則隨便選)

假如這個點所在的列的點數為奇數,與上面類似。

若不存在這樣的點呢?

那麼剩下的一定是所有行和列的點數皆為偶數。

那就隨便選擇乙個點i。把它刪掉。然後遞迴去求剩下m-1個點的情況。

那麼,點i所在的行和列的點數皆為奇數,假設現在的行(除去點i)的染色是紅》白,點i一定是白色。除去這個行,剩下的所有的點的紅白相等。除去這個列,紅白也相等。所以現在的列(除去點i)的染色也必定是紅》白。所以點i為白色是可行的。(若染色情況是白》紅,結果也是一樣的)

遞迴求解即可,時間複雜度:o(n^2)。

②上下界的網路流。

s與行連邊,下界為行數/2,上界為(行數+1)/2。

把每個點拆成一條邊(ai,bi),下界為0,上界為1。(若有流量,則選紅色)

t與列連邊,下界為列數/2,上界為(列數+1)/2。

ai與點i所在的行連邊,下界為0,上界為1。bi與點i所在的列連邊,下界為0,上界為1。

關於上下界網路流的構**析

【**】

//構造法

#include

#include

#include

using

namespace

std;

typedef

long

long ll;

const

int n=1500;

struct data d[n];

int w[n],n,t,row[n],lie[n],vis[n];

data ry[n],ly[n];

bool cmp1(int a,int b) else

ff=0;

break;}}

if(ff && yu!=-1)

}int main()

for(int i=1;i<=n;i++) scanf("%d%d",&d[i].a,&d[i].b),w[i]=i;

sort(w+1,w+1+n,cmp1);

int la=d[w[1]].a; d[w[1]].a=1; row[d[w[1]].a]++;

for(int i=2;i<=n;i++)

sort(w+1,w+1+n,cmp2);

la=d[w[1]].b; d[w[1]].b=1; lie[d[w[1]].b]++;

for(int i=2;i<=n;i++)

dfs(1);

for(int i=1;i<=n;i++) printf("%c",(vis[i]==2)?('w'):('r'));

printf("\n");

}return

0;}

//上下界網路流

#include

#include

#include

#include

#define imin(a,b) (((a)<(b))?(a):(b))

#define row(i) (i)

#define ia(i) (n+i)

#define ib(i) (n+n+i)

#define lie(i) (n+n+n+i)

using

namespace

std;

typedef

long

long ll;

const

int inf=1e9;

const

int n=1500;

struct data d[n];

int w[n],n,tt,row[n],lie[n];

int mh,ml,red[n];

const

int nn=1005000;

int to[nn],h[nn],ne[nn],val[nn],tt;

int lev[nn],vis[nn];

int s,t,sd,td,ru[nn],bfstime;

int q[nn],head,tail;

bool cmp1(int a,int b)

void ready()

bool bfs()

}return (vis[td]==bfstime);

}int dfs(int now,int maxf)

if(maxf) lev[now]=-1;

return ret;

}int dinic()

int main()

mh=d[w[n]].a;

sort(w+1,w+1+n,cmp2);

la=d[w[1]].b; d[w[1]].b=1; lie[d[w[1]].b]++;

for(int i=2;i<=n;i++)

ml=d[w[n]].b;

for(int i=1;i<=mh;i++)

for(int i=1;i<=ml;i++)

for(int i=1;i<=n;i++)

if(ru[s]>0) addedge(sd,s,ru[s]); else

if(ru[s]<0) addedge(s,td,-ru[s]);

if(ru[t]>0) addedge(sd,t,ru[t]); else

if(ru[t]<0) addedge(t,td,-ru[t]);

for(int i=1;i<=mh;i++)

for(int i=1;i<=ml;i++)

addedge(t,s,inf);

int maxflow=dinic();

for(int i=1;i<=n;i++) printf("%c",(val[red[i]]?('w'):('r')));

printf("\n");

}return

0;}

【題目描述】

【解題思路】

①首先確定的是,順序是沒關係的,只需求出來選數的方案數就成。因為選好了,一定可以按題意排好序的。

②把數按照模k的值分類。因為對答案有影響的也只是模數而已。

③揹包dp。f[i][j][h]表示做到了模為i的數,已經選了j個數,模數為h的方案數。

那麼,假設在模為i的數中選了g個數,選法有w種。

f[i][j+g][(h+g*i)%k]+=f[i-1][j][h]*w;

那,w怎麼求?

假設,模為i的有s個數。

那麼,就相當於把g個小球放入s個桶的方案數。

建立g個小球,再加入s-1個擋板。第i個擋板到第i-1個擋板之間的球就是桶i裡的小球個數,第s個桶的小球數為剩下的小球數(第s-1個擋板之後的小球)

只需求出放擋板的方案數,就是小球放入桶裡的方案數。

方案數=c(s+g-1,s-1),也就是c(s+g-1,g)

④因為c(n+m,n)=c(n+m,m),拓展證出,交換n,m的值,答案不變。

算組合方案時,要用到逆元……

【**】

#include

#include

#include

using namespace std;

typedef long long ll;

const int mods=2017;

int t,n,m,k;

int c[55],cs[5];

ll f[55][55][55],s

q[5][55];

ll pow(ll x,ll y)

returns;}

int main()

}for(int i=0;i<=m;i++) f[0][i][0]=s

q[c[0]][i];

for(int i=0;i1;i++)

for(int j=0;j<=m;j++)

for(int h=0;hif(f[i][j][h])

}printf("%lld\n",f[k-1][m][0]);

}return

0;}

【題目描述】

【解題思路】

按照題意模擬即可。

【**】

#include

#include

#include

int l,w;

int ans[1500];

int work(int o,char *o,int i)

}else

return o;

}int main()

NOIP2017提高組模擬賽4 (總結)

這道題就是很簡單的bfs,可以觀察到n變化到m是近似成倍增長的。其實從最小到最大的變化也就只有30次而已。include include include typedef long long ll using namespace std const int maxl 100 const int oo ...

NOIP2017提高組模擬賽5 (總結)

其實就是將乙個點f拆成向左l向右r的兩個點,然後將所有點排序 不用排序也行,直接找 選第乙個l,從後往前選第乙個不與l同乙個f的r。選最後乙個r,從前往後選第乙個不與r同乙個f的l。答案中的最大值即為兩點之間的最遠距離。證明如下 0 數學方法 把01看成a b個點。設s a b,x 最少要翻轉次數,...

NOIP2017提高組 模擬賽21(總結)

題目描述 解題思路 問題轉化為有多少個 l,r 使得a的l r這個區間乘起來是k的倍數。k 的時間分解k的質因數。列舉l,可以發現r具有單調性,也就是若 l,r 合法,那麼 l,r 1 也合法。用尺取法就可以解決。時間複雜度 o 2n k include include using namespac...