【題目描述】
【解題思路】
①構造法:
假設現在有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...