前言
- 比賽連結。
T1 寫得和正解差不多但少了個細節炸 long long
了;T2 只會 \(n^3\) 的本來只有 \(50pts\),但考慮出題人大機率會搞一個 \(n\) 越大 \(T\) 越小,所以對於 \(n\) 很大的直接 \(rand\) 正確率還是有的,所以獲得了 \(80pts\);T3 不會;T4 沒有和 \(n\) 取 \(\min\) 直接掛成 \(25pts\),好多人都因為這個掛分。
不過這次部分分給的很足好評。
T1
-
部分分 \(55pts\):對於 \(a_i\) 全為正數、\(|a_i|\le 1\)、樣例三個包分別處理。
-
正解:
考慮只有正數的資料,直接每次另 \(a_i+=a_{i-1}\) 即可,每次最多 \(+1e9\),最後最大為 \(1e14\),全是負數同理。
然後啟發正解,取一個 \(minn,maxx\),以 \(|maxx|\ge|minn|\) 為例,現將所有數都加上 \(maxx\) ,就變成了全是正數的情況;\(|maxx|<|minn|\) 同理全變成負數即可。
點選檢視程式碼
#include<bits/stdc++.h> #define ll long long #define endl '\n' #define sort stable_sort using namespace std; const int N=2e5+10; template<typename Tp> inline void read(Tp&x) { x=0;register bool z=true; register char c=getchar(); for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0; for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48); x=(z?x:~x+1); } template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);} template<typename Tp> inline void wt(Tp x) {if(x>9)wt(x/10);putchar((x%10)+'0');} template<typename Tp> inline void write(Tp x) {if(x<0)putchar('-'),x=~x+1;wt(x);} template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar(' ');write(y...);} int n,a[N],pos1,pos2; signed main() { read(n); for(int i=1;i<=n;i++) { read(a[i]); if(a[i]>a[pos1]) pos1=i; if(a[i]<a[pos2]) pos2=i; } if(!pos1||!pos2) { write(n-1),puts(""); if(!pos1) for(int i=n-1;i>=1;i--) write(i+1,i),puts(""); else for(int i=2;i<=n;i++) write(i-1,i),puts(""); } else { write(2*n-2),puts(""); if((-a[pos2])<=a[pos1]) { for(int i=1;i<=n;i++) if(i!=pos1) write(pos1,i),puts(""); for(int i=2;i<=n;i++) write(i-1,i),puts(""); } else { for(int i=1;i<=n;i++) if(i!=pos2) write(pos2,i),puts(""); for(int i=n-1;i>=1;i--) write(i+1,i),puts(""); } } }
T2
-
部分分 \(50+?pts\):\(n^3+rand\)。
-
正解:
隨一個 \(1\times n\) 的矩陣 \(d\),判斷 \(d\times a\times b\) 是否等於 \(d\times c\),複雜度就變成了 \(O(n^2)\),正確性我不會證明,但是錯誤率只有 \(\dfrac{1}{998244353}\)。
點選檢視程式碼
#include<bits/stdc++.h> #define ll long long #define endl '\n' #define sort stable_sort using namespace std; const int N=3010,P=998244353; template<typename Tp> inline void read(Tp&x) { x=0;register bool z=true; register char c=getchar(); for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0; for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48); x=(z?x:~x+1); } template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);} template<typename Tp> inline void wt(Tp x) {if(x>9)wt(x/10);putchar((x%10)+'0');} template<typename Tp> inline void write(Tp x) {if(x<0)putchar('-'),x=~x+1;wt(x);} template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar(' ');write(y...);} int T,n; ll d[N],ans1[N],ans2[N],ans3[N],a[N][N],b[N][N],c[N][N]; void add(ll &x,ll y) {x+=y; x=x>=P?x-P:x;} bool check(ll x[],ll y[]) { for(int i=1;i<=n;i++) if(x[i]!=y[i]) return 0; return 1; } signed main() { srand(time(0)); for(int i=1;i<=3000;i++) d[i]=rand()%P; read(T); while(T--) { read(n); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) read(a[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) read(b[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) read(c[i][j]); memset(ans1,0,sizeof(ans1)); memset(ans2,0,sizeof(ans2)); memset(ans3,0,sizeof(ans3)); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) add(ans1[i],d[j]*a[j][i]%P); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) add(ans2[i],ans1[j]*b[j][i]%P); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) add(ans3[i],d[j]*c[j][i]%P); puts(check(ans2,ans3)?"Yes":"No"); } }
T3
發現 \(k\) 很小,那麼對於每一行只有 \(2^k\) 中可能,將這 \(n\) 行組合起來,發現 \(2^k\) 中每一種狀態出現多次並不會影響連通性,那麼直接處理每種情況是否出現,那麼有 \(2^{2^k}\) 種狀態,爆搜判斷每種狀態是否合法,複雜度是不允許的,考慮打表,因為合法的狀態並不多。
之後就是計數,設一個總的狀態中共出現了 \(m\) 個 \(2^k\) 中的狀態,將其擴充套件到 \(n\) 列裡,等價於 \(n\) 個不同的球放 \(m\) 個不同的盒子裡,每個盒子至少放一個。
考慮容斥,發現對於不限制每個盒子至少放一個的情況為 \(m^n\),那麼這裡我欽定至少有 \(i\) 個是空的,那麼最後方案數就是:
上面打出來的表,\(num_{i,j}\) 表示 \(k=i\) 時,\(m=j\) 的合法狀態有多少,那麼最終答案為:
發現給 \(num_{k,i}\) 加上一個 \(0\) 的狀態就能夠轉移給 \(num_{k,i+1}\),所以每個 \(num_{k,i}\) 都要加上 \(num_{k,i-1}\) 的貢獻,注意不是字首和,要倒序列舉。
打表程式碼
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=1e4+10;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=true;
register char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x)
{if(x>9)wt(x/10);putchar((x%10)+'0');}
template<typename Tp> inline void write(Tp x)
{if(x<0)putchar('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar(' ');write(y...);}
ll ans[N];
bitset<N>vis;
vector<int>pos;
void check(int have,int k)
{
if(!have) return ;
int sta=0,tot=0;
sta|=pos[0];
while(k--) for(int i:pos)
if(i&sta) tot+=vis[i],vis[i]=0,sta|=i;
for(int i:pos) vis[i]=1;
if(tot==have) ans[tot]++;
}
void dfs(int x,int have,int k)
{
if(x==(1<<k)) {check(have,k); return ;}
dfs(x+1,have,k);
pos.push_back(x),vis[x]=1;
dfs(x+1,have+1,k);
pos.pop_back(),vis[x]=0;
}
signed main()
{
freopen("a.out","w",stdout);
for(int k=1;k<=5;k++)
{
vis.reset();
vector<int>().swap(pos);
memset(ans,0,sizeof(ans));
write(k),puts("");
dfs(1,0,k);
ans[0]=1;
for(int i=0;i<=31;i++) write(ans[i]),putchar(i!=31?',':' ');
puts(""),puts("");
}
}
表
1
1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
2
1,3,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
3
1,7,15,28,32,21,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
4
1,15,80,373,1222,2857,4918,6407,6431,5005,3003,1365,455,105,15,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
5
1,31,375,3860,28845,162440,720491,2603950,7856260,20127820,44327130,84657300,141113700,206250800,265182000,300540120,300540190,265182525,206253075,141120525,84672315,44352165,20160075,7888725,2629575,736281,169911,31465,4495,465,31,1
正解程式碼
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=1e4+10;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=true;
register char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x)
{if(x>9)wt(x/10);putchar((x%10)+'0');}
template<typename Tp> inline void write(Tp x)
{if(x<0)putchar('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar(' ');write(y...);}
ll num[6][35]=
{
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,3,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,7,15,28,32,21,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,15,80,373,1222,2857,4918,6407,6431,5005,3003,1365,455,105,15,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,31,375,3860,28845,162440,720491,2603950,7856260,20127820,44327130,84657300,141113700,206250800,265182000,300540120,300540190,265182525,206253075,141120525,84672315,44352165,20160075,7888725,2629575,736281,169911,31465,4495,465,31,1}
};
ll n,m,k,P,ans,sum,jc[N],inv[N];
ll qpow(ll a,ll b)
{
ll ans=1;
for(;b;b>>=1)
{
if(b&1) (ans*=a)%=P;;
(a*=a)%=P;
}
return ans;
}
ll C(ll n,ll m)
{
if(m>n) return 0;
if(m==0||m==n) return 1;
return jc[n]*inv[n-m]%P*inv[m]%P;
}
signed main()
{
read(n,k,P); m=min(n,1ll<<k);
jc[0]=1;
for(int i=1;i<=m;i++) jc[i]=jc[i-1]*i%P;
inv[m]=qpow(jc[m],P-2);
for(int i=m-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%P;
for(int i=m;i>=1;i--) num[k][i]+=num[k][i-1];
for(int i=1;i<=m;i++)
{
sum=0;
for(int j=i,op=1;j>=1;j--,op=-op)
(sum+=op*C(i,j)%P*qpow(j,n)%P+P)%=P;
(ans+=sum*num[k][i]%P)%=P;
}
write(ans);
}
T4
挺簡單一道 DP,\(O(nv^2)\) 的肯定都會,考慮 \(n\) 很小,\(f_{i,i,j}\) 表示前 \(i\) 個數中選 \(j\) 個 \(\sum a=k\) 時 \(\sum b\) 最小為多少,最後暴力掃一遍統計答案。
注意最後求出來的 \(ans\) 要 \(+1\) 因為題目要求的是第一個大於的,但其最大為 \(n\),所以要和 \(n\) 取 \(\min\)!qwq
最後複雜度為 \(O(n^2v)\),即使這樣空間也很難受,可以滾掉一維。
點選檢視程式碼
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=85,M=1e4+10;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=true;
register char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x)
{if(x>9)wt(x/10);putchar((x%10)+'0');}
template<typename Tp> inline void write(Tp x)
{if(x<0)putchar('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar(' ');write(y...);}
int n,mx_a,mx_b,ans,a[N],b[N],f[N][M];
signed main()
{
read(n,mx_a,mx_b);
for(int i=1;i<=n;i++) read(a[i],b[i]);
memset(f,0x3f,sizeof(f));
f[0][0]=0;
for(int i=1;i<=n;i++)
for(int j=i;j>=1;j--)
for(int k=mx_a;k>=a[i];k--)
{
f[j][k]=min(f[j][k],f[j-1][k-a[i]]+b[i]);
ans=f[j][k]<=mx_b&&ans<j?j:ans;
}
write(min(n,ans+1));
}
總結
好好理解題意,T1、T4 都因為這個掛分了。
附錄
熟悉的:
請注意:題目背景與題目可能沒有關係。
所以題名和背景:
A 符號化方法初探
B 無標號 Sequence 構造
C 無標號 Multiset 構造
D 有限制的構造