这场考试我其实并没有参加......
因为一些奥妙重重的原因肚子疼到厌生,没看完题就滚回家了......
马上就NOI了还是这种身体状态,真是要完。
T1:
我们先把所有点双联通分量缩起来。
如果这个双联通分量只有一条边,那么方案数显然是k;
如果这个双联通分量恰好是一个环,那么方案数可以用polya定理计算;
否则,这个双联通分量的任意两条边可以互换颜色(自行构造一下就知道了),所以方案数只和某种颜色出现几次有关,大力插板即可。
双联通分量的形态怎么判?记录点数和边数判断即可。
具体就是用vector存下来每个分量的每条边,然后暴力数点即可。
(这里吐槽一句求点双联通分量栈里面压点的都是邪教!你那么做根本没法统计返祖边!)
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #include<cctype> 7 #define debug cout 8 typedef long long int lli; 9 using namespace std; 10 const int maxn=5e5+1e2,maxe=1e6+1e2; 11 const int mod=1e9+7; 12 13 int inv[maxe]; 14 inline int mul(const int &x,const int &y) { 15 return (lli) x * y % mod; 16 } 17 inline void adde(int &dst,const int &x) { 18 if( ( dst += x ) >= mod ) dst -= mod; 19 } 20 inline void mule(int &dst,const int &x) { 21 dst = (lli) dst * x % mod; 22 } 23 inline int fastpow(int base,int tim) { 24 int ret = 1; 25 while(tim) { 26 if( tim & 1 ) mule(ret,base); 27 if( tim >>= 1 ) mule(base,base); 28 } 29 return ret; 30 } 31 inline int c(int x,int y) { 32 int ret = 1; 33 for(int i=0;i<y;i++) mule(ret,x-i); 34 for(int i=1;i<=y;i++) mule(ret,inv[i]); 35 return ret; 36 } 37 inline int gcd(int x,int y) { 38 register int t; 39 while( t = x % y ) x = y , y = t; 40 return y; 41 } 42 43 int u[maxe],v[maxe]; 44 int s[maxn],t[maxe<<1],nxt[maxe<<1]; 45 int dfn[maxn],low[maxn],stk[maxe],top,fs; 46 vector<int> es[maxn<<1]; 47 bool vis[maxn]; 48 int n,m,k,ans=1; 49 50 inline void coredge(int from,int to) { 51 static int cnt = 1; 52 t[++cnt] = to , nxt[cnt] = s[from] , s[from] = cnt; 53 } 54 inline void addedge(int a,int b) { 55 coredge(a,b) , coredge(b,a); 56 } 57 inline void dfs(int pos,int sou) { 58 static int dd; low[pos] = dfn[pos] = ++dd , vis[pos] = 1; 59 for(int at=s[pos];at;at=nxt[at]) if( at != ( sou ^ 1 ) ) { 60 if( !vis[t[at]] ) { 61 stk[++top] = at; 62 dfs(t[at],at) , low[pos] = min( low[pos] , low[t[at]] ); 63 if( low[t[at]] >= dfn[pos] ) { 64 int x; ++fs; 65 do es[fs].push_back((x=stk[top--])>>1); while( x != at ); 66 } 67 } else { 68 if( dfn[t[at]] < dfn[pos] ) stk[++top] = at; 69 low[pos] = min( low[pos] , dfn[t[at]] ); 70 } 71 } 72 } 73 inline void calc_ring(const vector<int> &vec) { 74 if( vec.size() == 1 ) return mule(ans,k); 75 int ps = 0; 76 for(unsigned i=0;i<vec.size();i++) { 77 if( !vis[u[vec[i]]] ) ps += vis[u[vec[i]]] = 1; 78 if( !vis[v[vec[i]]] ) ps += vis[v[vec[i]]] = 1; 79 } 80 for(unsigned i=0;i<vec.size();i++) vis[u[vec[i]]] = vis[v[vec[i]]] = 0; 81 if( ps == (signed)vec.size() ) { 82 int ret = 0; 83 for(int i=1;i<=ps;i++) adde(ret,fastpow(k,gcd(i,ps))); 84 mule(ret,inv[ps]) , mule(ans,ret); 85 } else mule(ans,c(k+vec.size()-1,vec.size())); 86 } 87 88 inline void init() { 89 inv[0] = inv[1] = 1; 90 for(int i=2;i<=m;i++) inv[i] = mul(mod-mod/i,inv[mod%i]); 91 } 92 93 inline int getint() { 94 int ret = 0 , ch; 95 while( !isdigit(ch=getchar()) ); 96 do ret = ret * 10 + ch - '0'; while( isdigit(ch=getchar()) ); 97 return ret; 98 } 99 100 int main() { 101 n = getint() , m = getint() , k = getint() , init(); 102 for(int i=1;i<=m;i++) addedge(u[i]=getint(),v[i]=getint()); 103 for(int i=1;i<=n;i++) if( !vis[i] ) dfs(i,0); 104 memset(vis,0,sizeof(vis)); 105 for(int i=1;i<=fs;i++) calc_ring(es[i]); 106 printf("%d ",ans); 107 return 0; 108 }
T2:
我会有下界的最小流!
等等,为什么要按照上下界建图呢?直接从钦定边全选的状态开始退流就行了,限制每个点能退的流量。水题!
然而SPJ还得自己改......
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #include<cctype> 7 #define debug cout 8 using namespace std; 9 const int maxn=4e3+1e2,maxe=8e3+1e2; 10 const int inf=0x3f3f3f3f; 11 12 int u[maxn],v[maxn],deg[maxn]; 13 int n1,n2,m,mi=inf; 14 15 namespace NetworkFlow { 16 int s[maxn],t[maxe],nxt[maxe],f[maxe],cnt; 17 int dep[maxn],st,ed; 18 inline void coredge(int from,int to,int flow) { 19 t[++cnt] = to , f[cnt] = flow , nxt[cnt] = s[from] , s[from] = cnt; 20 } 21 inline void singledge(int from,int to,int flow) { 22 coredge(from,to,flow) , coredge(to,from,0); 23 } 24 inline bool bfs() { 25 memset(dep,-1,sizeof(dep)) , dep[st] = 0; 26 queue<int> q; q.push(st); 27 while( q.size() ) { 28 const int pos = q.front(); q.pop(); 29 for(int at=s[pos];at;at=nxt[at]) if( f[at] && !~dep[t[at]] ) { 30 dep[t[at]] = dep[pos] + 1 , q.push(t[at]); 31 } 32 } 33 return ~dep[ed]; 34 } 35 inline int dfs(int pos,int flow) { 36 if( pos == ed ) return flow; 37 int ret = 0 , now = 0; 38 for(int at=s[pos];at;at=nxt[at]) if( f[at] && dep[t[at]] > dep[pos] ) { 39 now = dfs(t[at],min(flow,f[at])) , ret += now , flow -= now , f[at] -= now , f[at^1] += now; 40 if( !flow ) return ret; 41 } 42 if( !ret ) dep[pos] = -1; 43 return ret; 44 } 45 inline int dinic() { 46 int ret = 0; 47 while( bfs() ) ret += dfs(st,inf); 48 return ret; 49 } 50 inline void reset() { 51 memset(s,0,sizeof(s)) , cnt = 1; 52 } 53 } 54 55 inline void build(int k) { 56 NetworkFlow::reset() , NetworkFlow::st = n1 + n2 + 1 , NetworkFlow::ed = n1 + n2 + 2; 57 for(int i=1;i<=m;i++) NetworkFlow::singledge(n1+v[i],u[i],1); 58 for(int i=1;i<=n1;i++) NetworkFlow::singledge(i,NetworkFlow::ed,deg[i]-k); 59 for(int i=n1+1;i<=n1+n2;i++) NetworkFlow::singledge(NetworkFlow::st,i,deg[i]-k); 60 } 61 inline void printans() { 62 static int seq[maxn],sql; sql = 0; 63 using namespace NetworkFlow; dinic(); 64 for(int i=1;i<=m;i++) if( f[i<<1] ) seq[++sql] = i; 65 sort(seq+1,seq+1+sql) , printf("%d ",sql); 66 for(int i=1;i<=sql;i++) printf("%d ",seq[i]); 67 putchar(' '); 68 } 69 70 inline int getint() { 71 int ret = 0 , ch; 72 while( !isdigit(ch=getchar()) ); 73 do ret = ret * 10 + ch - '0'; while( isdigit(ch=getchar()) ); 74 return ret; 75 } 76 77 int main() { 78 n1 = getint() , n2 = getint() , m = getint(); 79 for(int i=1;i<=m;i++) ++deg[u[i]=getint()] , ++deg[n1+(v[i]=getint())]; 80 for(int i=1;i<=n1+n2;i++) mi = min( mi , deg[i] ); 81 for(int i=0;i<=mi;i++) build(i) , printans(); 82 return 0; 83 }
SPJ:
1 #include<cstdio> 2 #define WA return puts("0"),0 3 #define AC return puts("4"),0 4 int n1,n2,m,u[2010],v[2010],md,ans[2010],deg[2][2010]; 5 bool used[2010]; 6 int full; 7 int main(int argc,char*argv[]){ 8 freopen(argv[1],"r",stdin); 9 scanf("%d%d%d",&n1,&n2,&m); 10 for(int i=0;i<m;i++)scanf("%d%d",u+i,v+i); 11 freopen(argv[3],"r",stdin); 12 md=-1; 13 while(scanf("%d",ans+(++md))==1){ 14 for(int i=ans[md];i--;)scanf("%*d"); 15 } 16 md--; 17 freopen(argv[2],"r",stdin); 18 freopen(argv[5],"w",stdout); 19 for(int i=0;i<=md;i++){ 20 int c; 21 if(scanf("%d",&c)!=1||c!=ans[i])WA; 22 for(int j=0;j<m;j++)used[j]=0; 23 for(int j=0;j<n1;j++)deg[0][j]=0; 24 for(int j=0;j<n2;j++)deg[1][j]=0; 25 while(c--){ 26 int x; 27 if(scanf("%d",&x)!=1||x<1||x>m||used[x-1])WA; 28 used[--x]=1; 29 deg[0][u[x]]++; 30 deg[1][v[x]]++; 31 } 32 for(int j=1;j<=n1;j++)if(deg[0][j]<i)WA; 33 for(int j=1;j<=n2;j++)if(deg[1][j]<i)WA; 34 } 35 AC; 36 }
T3:
一脸不可做的样子......
考虑对每个点统计覆盖它的圆的贡献。
我们先计算第一象限(含x轴)的答案,最后乘4在加上原点的贡献即可。
考虑枚举点的坐标,我们有:
(后面j是在枚举能覆盖这个点的圆,后面乘的是这个圆被统计的次数)
我们令:
显然关于x的k次多项式的前缀和或有上界的后缀和都是一个关于x的k+1次多项式。所以这个s我们能拉格朗日插值。
那么我们的公式能化为:
我们令:
就是一个把x当做常数,关于y的函数了。
我们理性分析一下,S(x)是关于x的3次多项式,那么S(x^2+y^2)就是关于y的6次多项式,而这个东西是S(x^2+y^2)的前缀和,就是关于y的7次多项式喽。
于是我们又能大力拉格朗日插值......
然后我们枚举x,这题就做完了......复杂度O(sqrt(m)),常数巨大,最后一个点要7s......
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #define debug cout 7 typedef long long int lli; 8 using namespace std; 9 const int mod=1e9+7; 10 11 inline int add(const int &x,const int &y) { 12 const int ret = x + y; 13 return ret >= mod ? ret - mod : ret; 14 } 15 inline int sub(const int &x,const int &y) { 16 const int ret = x - y; 17 return ret < 0 ? ret + mod : ret; 18 } 19 inline int mul(const int &x,const int &y) { 20 return (lli) x * y % mod; 21 } 22 inline void adde(int &dst,const int &x) { 23 if( ( dst += x ) >= mod ) dst -= mod; 24 } 25 inline void sube(int &dst,const int &x) { 26 if( ( dst -= x ) < 0 ) dst += mod; 27 } 28 inline void mule(int &dst,const int &x) { 29 dst = (lli) dst * x % mod; 30 } 31 inline int fastpow(int base,int tim) { 32 int ret = 1; 33 while(tim) { 34 if( tim & 1 ) mule(ret,base); 35 if( tim >>= 1 ) mule(base,base); 36 } 37 return ret; 38 } 39 40 struct Interval { 41 int xs[11],ys[11],ps[11],cnt; 42 inline void insert(const int &x,const int &y) { 43 xs[++cnt] = x , ys[cnt] = y; 44 } 45 inline void init() { 46 for(int i=1;i<=cnt;i++) { 47 ps[i] = 1; 48 for(int j=1;j<=cnt;j++) if( j != i ) mule(ps[i],sub(xs[i],xs[j])); 49 ps[i] = fastpow(ps[i],mod-2); 50 } 51 } 52 inline int calc(const int &x) { 53 int ret = 0; 54 for(int i=1;i<=cnt;i++) { 55 int pi = 1; 56 for(int j=1;j<=cnt;j++) if( j != i ) mule(pi,sub(x,xs[j])); 57 adde(ret,mul(mul(pi,ps[i]),ys[i])); 58 } 59 return ret; 60 } 61 inline void reset() { 62 cnt = 0; 63 } 64 }s,f; 65 66 lli m; 67 int sq,ans; 68 69 inline void inits() { 70 const int m = ::m % mod; 71 for(int i=m,su;i>m-4;i--) { 72 su = 0; 73 for(int j=i;j<=m;j++) adde(su,mul(j,sub((m+1)%mod,j))); 74 s.insert(i,su); 75 } 76 s.init(); 77 } 78 inline void initf(int x) { 79 f.reset(); 80 for(int i=1,su=0;i<=8;i++) adde(su,s.calc(((lli)x*x+i*i)%mod)) , f.insert(i,su); 81 f.init(); 82 } 83 84 int main() { 85 scanf("%lld",&m) , inits() , sq = sqrt(m); 86 for(int i=0;i<=sq;i++) { 87 if( (lli) i * i + 8 * 8 <= m ) initf(i) , adde(ans,f.calc((lli)sqrt(m-(lli)i*i)%mod)); 88 else { 89 int t = sqrt(m-(lli)i*i); 90 for(int j=1;j<=t;j++) adde(ans,s.calc(((lli)i*i+j*j)%mod)); 91 } 92 } 93 mule(ans,4) , adde(ans,s.calc(0)) , printf("%d ",ans); 94 return 0; 95 }
夜(よる)が明(あ)けて朝(あさ)が来(く)る
黑夜终去 黎明终来
星空(ほしぞら)が朝(あさ)に溶(と)けても
繁星即使融化于晨
君(きみ)の辉(かがや)きはわかるよ
我依可见君之光辉
思(おも)い出(で)を羽(は)ばたかせ
思念化为羽翼
君(きみ)の空(そら)へ舞(ま)い上(あ)がる
飞向星之所在