牛客IOI周賽21-提高組
阿新 • • 發佈:2020-12-27
比賽連結:https://ac.nowcoder.com/acm/contest/9798#question
題號 | 標題 | 已通過程式碼 | 通過率 | 我的狀態 |
---|---|---|---|---|
A | 序列問題 | 點選檢視 | 34/406 | 通過 |
B | 俄羅斯方塊 | 點選檢視 | 19/406 | 通過 |
C | 旅行沒有商問題 | 點選檢視 | 20/96 | 未通過 |
A
推式子題,主要是細節特別多。討論 \(q\) 的範圍,分 5 類。
只需 \(B_{min}-A_{max} \geq q\)
令 \(i=A_{max},j=B_{min}\) , 考慮列舉 \(i,j\),則 \(A,B\) 集合中的其他數分別在 \([1,i-1],[j+1,n]\) 中任取。
易得:
\[ans=\sum _{i=1}^{n} 2^{i-1} \times \sum_{j=max\{i+q,1\}}^{n} 2^{n-j} \]由於此式不能優美地化簡,對 \(q\) 分類。
-
$q \geq n $ 時, \(ans=0\).
-
\(q \in [0,n-1]\) 時,
\[ans=\sum _{i=1}^{n-q} 2^{i-1} \times \sum_{j=i+q}^{n} 2^{n-j} \]\[= \sum _{i=1}^{n-q} 2^{i-1} \times (2^{n-i-q+1}-1) \]\[= (n-q-1) \times 2^{n-q} +1 \] -
\(q\in [-n+1,-1]\) 時,有兩類,別漏了第二類。
\[ans=\sum _{i=|q|+1}^{n} 2^{i-1} \times \sum_{j=i+q}^{n} 2^{n-j}+\sum _{i=1}^{|q|} 2^{i-1} \times \sum_{j=1}^{n} 2^{n-j} \]\[= \sum _{i=|q|+1}^{n-q} 2^{i-1} \times (2^{n-i-q+1}-1)+(2^{|q|}-1)\times (2^n-1) \]\[=(n-|q|)\times 2^{n+|q|}-2^n+2^{|q|}+(2^{|q|}-1)\times (2^n-1) \] -
\(q \leq -n\) 時,隨便選 \(ans=(2^n-1)^2\)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const LL MOD=998244353;
LL fpow(LL x,LL k,LL MOD)
{
LL res=1; x%=MOD;
while(k) {
if(k&1) res=res*x%MOD;
x=x*x%MOD; k>>=1;
}
return res;
}
int T;
LL n,q;
int main()
{
// freopen("1.in","r",stdin);
scanf("%d",&T);
while(T--) {
scanf("%lld%lld",&n,&q);
if(q>=n) printf("0\n");
else if(q>=0) printf("%lld\n",((n-q-1)%MOD*fpow(2,n-q,MOD)%MOD+1+MOD)%MOD);
else if(n+q<=0) printf("%lld\n",(fpow(2,n,MOD)-1)*(fpow(2,n,MOD)-1)%MOD);
else if(q<0) printf("%lld\n",
(((n+q)%MOD*fpow(2,n-q,MOD)%MOD-fpow(2,n,MOD)+fpow(2,-q,MOD))%MOD+
(fpow(2,-q,MOD)-1)*(fpow(2,n,MOD)-1)%MOD+MOD)%MOD);
}
return 0;
}
B
B 是 大模擬,類似於 瑪雅游戲。
type=1 有 2 類,type=2 有 1 類,type=3 有4類。
我不太想寫,於是寫一類交一次。
最後,我只考慮了 6 類就 A 了。
資料太水。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N=11,INF=0x3f3f3f3f;
struct State
{
int a[N][N];
int tot;
State() { memset(a,0,sizeof a); tot=0; }
int get_height(int x)
{
for(int j=7;j>=1;j--)
if(a[j][x]) return j;
return 0;
}
void suit()
{
int i,j,flag,k;
for(i=7;i>=1;i--) {
flag=0;
for(j=1;j<=6;j++)
if(a[i][j]) flag++;
if(flag==6) {
for(k=i;k<=7;k++) {
for(j=1;j<=6;j++) {
a[k][j]=a[k+1][j];
}
}
tot++;
suit();
return;
}
}
}
void print() const
{
puts("===========================");
int i,j;
for(i=7;i>=1;i--,printf("\n"))
for(j=1;j<=6;j++)
printf("%d ",a[i][j]);
puts("===========================");
}
};
int n;
int type[N];
int ans;
void dfs(int step,State s)
{
// s.print();
if(step==n+1) {
ans=max(ans,s.tot);
return;
}
int i,j,h;
State v;
if(type[step]==1) {
// 橫著放。
for(i=0;i<3;i++) {
v=s;
h=0;
for(j=1;j<=4;j++)
h=max(h,v.get_height(i+j));
if(h+1<=7) {
for(j=1;j<=4;j++)
v.a[h+1][i+j]=1;
v.suit();
dfs(step+1,v);
}
}
// 豎著放。
for(i=1;i<=6;i++) {
v=s;
h=v.get_height(i);
if(h+4<=7) {
for(j=1;j<=4;j++) v.a[h+j][i]=1;
// v.print();
v.suit();
// v.print();
dfs(step+1,v);
}
}
}
else if(type[step]==2) {
for(i=0;i<5;i++) {
v=s;
h=0;
for(j=1;j<=2;j++) {
h=max(h,v.get_height(i+j));
}
if(h+2<=7) {
// v.print();
for(j=1;j<=2;j++)
v.a[h+1][i+j]=v.a[h+2][i+j]=1;
// v.print();
v.suit();
// v.print();
dfs(step+1,v);
}
}
}
else if(type[step]==3) {
// A.
for(i=0;i<4;i++) {
v=s,h=0;
for(j=1;j<=3;j++)
h=max(h,v.get_height(i+j));
if(h+2<=7) {
for(j=1;j<=3;j++)
v.a[h+1][i+j]=1;
v.a[h+2][i+3]=1;
v.suit();
dfs(step+1,v);
}
}
// B.
for(i=0;i<5;i++) {
v=s,h=0;
for(j=1;j<=2;j++) {
h=max(h,v.get_height(i+j));
}
if(h+3<=7) {
v.a[h+1][i+1]=1;
v.a[h+2][i+1]=1;
v.a[h+3][i+1]=1;
v.a[h+1][i+2]=1;
v.suit();
dfs(step+1,v);
}
}
// C.
// ***
// *
for(i=0;i<4;i++) {
v=s; h=0;
h=max(h,v.get_height(i+1)+1);
h=max(h,v.get_height(i+2));
h=max(h,v.get_height(i+3));
if(h+1<=7) {
v.a[h][i+1]=1;
v.a[h+1][i+1]=1;
v.a[h+1][i+2]=1;
v.a[h+1][i+3]=1;
v.suit();
dfs(step+1,v);
}
}
}
}
int main()
{
// freopen("1.in","r",stdin);
int i;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&type[i]);
State s;
dfs(1,s);
cout<<ans<<endl;
return 0;
}
話說輸出 (n+1)/2 能獲得 70pts.
其實熟悉了此類dfs,寫起來也不難。
C
連結:https://ac.nowcoder.com/acm/contest/9798/C
來源:牛客網給出n個點,m條邊的無向圖。滿足無重邊、自環,不保證連通。某人在圖上依次訪問d個節點(即所經過的所有節點構成的序列長度為d)。n個點中有k個點必須至少經過一次。起點、終點任選。求滿足條件的方案數對109+7取模的值
想了一個狀壓,然後用矩乘優化,80pts.
#include<queue>
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N=20+1;
const LL MOD=1e9+7;
int n,m,day,city;
LL f[N][64],g[N][64];
// f[i][j][k] 表示 經過了 i 個城市,現在在 j , 經過想要城市的點集為 k 的方案數。
int a[N];
int w[N][N];
void solve()
{
int i,j,k,u,v;
for(i=0;i<n;i++) {
if(~a[i]) f[i][1<<a[i]]=1;
else f[i][0]=1;
}
for(i=2;i<=day;i++) {
// for(k=0;k<(1<<city);k++)
// for(j=0;j<n;j++)
// printf("f[%d][%d] = %lld\n",j,k,f[j][k]);
memcpy(g,f,sizeof g);
memset(f,0,sizeof f);
for(k=0;k<(1<<city);k++) {
for(j=0;j<n;j++) {
if(~a[j] && !((k>>a[j])&1)) continue;
if(~a[j]) {
u=k-(1<<a[j]);
for(v=0;v<n;v++) {
if(~a[v] && !((u>>a[v])&1)) continue;
if(!w[j][v]) continue;
f[j][k]=(f[j][k]+g[v][u])%MOD;
}
}
u=k;
for(v=0;v<n;v++) {
if(~a[v] && !((u>>a[v])&1)) continue;
if(!w[j][v]) continue;
f[j][k]=(f[j][k]+g[v][u])%MOD;
}
}
}
}
LL ans=0;
for(i=0;i<n;i++)
ans=(ans+f[i][(1<<city)-1])%MOD;
printf("%lld\n",ans%MOD);
}
int get(int x,int y) { return x*(1<<city)+y+1; }
struct Matrix
{
LL a[2000][2000];
int n,m;
Matrix(int n=0,int m=0) : n(n),m(m) {
memset(a,0,sizeof a);
}
};
Matrix mul(const Matrix &x,const Matrix &y)
{
Matrix z;
z.n=x.n,z.m=y.m;
int i,j,k;
for(i=1;i<=z.n;i++) {
for(j=1;j<=z.m;j++) {
for(k=1;k<=y.n;k++)
z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%MOD)%MOD;
}
}
return z;
}
Matrix fpow(Matrix x,LL k,Matrix res)
{
while(k) {
if(k&1) res=mul(x,res);
x=mul(x,x); k>>=1;
}
return res;
}
void print(Matrix x)
{
for(int i=1;i<=x.n;i++,printf("\n"))
for(int j=1;j<=x.m;j++)
printf("%lld ",x.a[i][j]);
printf("\n");
}
void Work()
{
int i,j,k,u,v;
const int S=(1<<city);
const int Row=get(n-1,S);
Matrix A(Row,1);
Matrix C(Row,Row);
for(i=0;i<n;i++) {
if(~a[i]) A.a[get(i,1<<a[i])][1]=1;
else A.a[get(i,0)][1]=1;
}
// print(A);
for(k=0;k<(1<<city);k++) {
for(j=0;j<n;j++) {
if(~a[j] && !((k>>a[j])&1)) continue;
if(~a[j]) {
u=k-(1<<a[j]);
for(v=0;v<n;v++) {
if(~a[v] && !((u>>a[v])&1)) continue;
if(!w[j][v]) continue;
C.a[get(j,k)][get(v,u)]++;
}
}
u=k;
for(v=0;v<n;v++) {
if(~a[v] && !((u>>a[v])&1)) continue;
if(!w[j][v]) continue;
C.a[get(j,k)][get(v,u)]++;
}
// print(C);
}
}
A=fpow(C,day-1,A);
// print(C);
// print(A);
LL ans=0;
for(i=0;i<n;i++)
ans=(ans+A.a[get(i,(1<<city)-1)][1])%MOD;
printf("%lld\n",ans%MOD);
}
int main()
{
// freopen("1.in","r",stdin);
int i;
int x,y;
cin>>n>>m>>day>>city;
memset(a,-1,sizeof a);
for(i=0;i<city;i++) {
cin>>x;
x--;
a[x]=i;
}
for(i=1;i<=m;i++) {
cin>>x>>y;
x--,y--;
w[x][y]=w[y][x]=1;
}
// if(day<=1000 || n<=5) solve();
Work();
return 0;
}
正解咕咕咕中。