2023 ICPC Gran Premio de Mexico 2da Fecha
思路:考虑贪心,即每次只需拆出一个数字,因为1,2,3,4,5,7,9
都符合条件,而剩下的0,6,8
这3个数无论怎么组合都无法满足条件(坑点:0
不算完全平方数)。复杂度 O ( n ) O(n) O(n)。
#include
#define fi first
#define se second
#define lson (k<<1)
#define rson (k<<1)+1
#define mid ((l+r)/2)
#define sz(x) int(x.size())-1
#define pii pair<int,int>
#define bit bitset<100000>
using namespace std;
const int MAX=1e6+10;
const int MOD=1e9+7;
const double PI=acos(-1.0);
typedef long long ll;
char s[MAX];
int solve()
{
int n,ans=0;
scanf("%d%s",&n,s);
for(int i=0;i<n;i++)ans+=(s[i]!='0'&&s[i]!='6'&&s[i]!='8');
return printf("%d\n",ans);
}
int main()
{
int T=1;
// cin>>T;
while(T--)solve();
return 0;
}
思路:求多重集的排列数。复杂度 O ( k ∗ log 2 1 0 9 ) O(k*\log_210^9) O(k∗log2109)。
#include
#define fi first
#define se second
#define lson (k<<1)
#define rson (k<<1)+1
#define mid ((l+r)/2)
#define sz(x) int(x.size())-1
#define pii pair<int,int>
#define bit bitset<100000>
using namespace std;
const int MAX=1e6+10;
const int MOD=1e9+7;
const double PI=acos(-1.0);
typedef long long ll;
ll POW(ll x,ll n)
{
ll res=1;
while(n)
{
if(n&1)res=res*x%MOD;
x=x*x%MOD;
n>>=1;
}return res;
}
ll fac[MAX],a[MAX];
map<int,int>c;
int solve()
{
int n,q;
cin>>n>>q;
fac[1]=1;
for(int i=2;i<=n;i++)fac[i]=fac[i-1]*i%MOD;
ll ans=POW(fac[n],MOD-2);
for(int i=1;i<=n;i++)
{
scanf("%d",a+i);
c[a[i]]++;
}
for(auto &kv:c)ans=ans*fac[kv.second]%MOD;
printf("%lld\n",ans);
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
ans=ans*POW(c[a[x]],MOD-2)%MOD;
c[a[x]]--;
c[y]++;
a[x]=y;
ans=ans*c[y]%MOD;
printf("%lld\n",ans);
}
return 0;
}
int main()
{
int T=1;
while(T--)solve();
return 0;
}
思路:考虑枚举 H H H最大值。利用单调栈我们可以得到一个个分隔且互不覆盖的区间 [ L 1 , R 1 ] , [ L 2 , R 2 ] , . . . . , [ L k , R k ] [L_1,R_1],[L_2,R_2],....,[L_k,R_k] [L1,R1],[L2,R2],....,[Lk,Rk]。
这些区间内的最大值均为 H H H,同时我们也知道这些区间中值为 H H H的数的下标。
于是我们可以分别求出各个区间内满足最大值为 H H H的子区间的个数 c 1 , c 2 , . . . , c k c_1,c_2,...,c_k c1,c2,...,ck。
那么各区间之前相互组合满足答案的方案数为
s = c 1 ∗ ( c 2 + c 3 + . . . + c k ) + c 2 ∗ ( c 3 + . . . + c k ) + . . . + c k − 1 ∗ c k \begin{aligned} s=&c_1*(c_2+c_3+...+c_k)\\ &+c_2*(c_3+...+c_k)\\ &+...\\ &+c_{k-1}*c_k \end{aligned} s=c1∗(c2+c3+...+ck)+c2∗(c3+...+ck)+...+ck−1∗ck
接下来只需求出各个区间内组合满足条件的方案数 s i s_i si,并累计至答案即可。
求 s i s_i si,考虑用后缀和统计好满足条件的区间数,然后遍历区间的最大值 H H H的下标 x x x,将 [ L i , R i ] [L_i,R_i] [Li,Ri]分成2半 [ L i , x ] , [ x , R i ] [L_i,x],[x,R_i] [Li,x],[x,Ri],并利用前缀和方案数和后缀和方案数计算(用等差数列计算)出符合条件的不覆盖方案数。
复杂度 O ( n ) O(n) O(n)。
#include
#define fi first
#define se second
#define lson (k<<1)
#define rson (k<<1)+1
#define mid ((l+r)/2)
#define sz(x) int(x.size())
#define pii pair<ll,ll>
#define bit bitset<100000>
using namespace std;
const int MAX=2e6+10;
const int MOD=1e9+7;
const double PI=acos(-1.0);
typedef long long ll;
vector<int>p[MAX];
int h[MAX],L[MAX],R[MAX];
int init(int n)
{
stack<int>s;
for(int i=1;i<=n;i++)
{
p[h[i]].push_back(i);
while(!s.empty()&&h[s.top()]<=h[i])s.pop();
L[i]=(s.empty()?0:s.top())+1;
s.push(i);
}
while(!s.empty())s.pop();
for(int i=n;i>=1;i--)
{
while(!s.empty()&&h[s.top()]<=h[i])s.pop();
R[i]=(s.empty()?n:(s.top()-1));
s.push(i);
}
return 0;
}
ll cal(int m)
{
ll sum=0;
ll pre=0;
for(int i=0;i<sz(p[m]);)
{
ll l=L[p[m][i]];
ll r=R[p[m][i]];
vector<ll> tmp;
while(i<sz(p[m])&&p[m][i]<=r)
{
tmp.push_back(p[m][i]);
i++;
}
ll ex=0;
for(int j=0;j+1<sz(tmp);j++)(ex+=((tmp[j+1]-tmp[j])*(tmp[j+1]-tmp[j]-1)/2)%MOD)%=MOD;
ex+=((tmp[0]-l+1)*(tmp[0]-l)/2)%MOD;
ex+=((r-tmp.back()+1)*(r-tmp.back())/2)%MOD;
ex%=MOD;
ll now=(((r-l+1+1)*(r-l+1)/2)%MOD-ex+MOD)%MOD;
(sum+=now*pre%MOD)%=MOD;
(pre+=now)%=MOD;
ll suf=0;
for(int j=0;j<sz(tmp);j++)(suf+=(tmp[j]-(j==0?l-1:tmp[j-1]))*(r-tmp[j]+1)%MOD)%MOD;
for(int j=0;j+1<sz(tmp);j++)
{
suf-=(tmp[j]-(j==0?l-1:tmp[j-1]))*(r-tmp[j]+1)%MOD;
suf=(suf%MOD+MOD)%MOD;
ll k=tmp[j]-l+1;
ll d=r-tmp[j+1]+1;
ll c=tmp[j+1]-tmp[j]-1;
sum+=k*((c+1)*suf%MOD-(c*d*(c+1)/2)%MOD+MOD)%MOD;
sum%=MOD;
}
}
return sum;
}
int solve()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)scanf("%d",h+i);
init(n);
ll ans=0;
for(int i=1;i<=n;i++)ans=(ans+cal(i))%MOD;
printf("%lld\n",ans);
return 0;
}
int main()
{
int T=1;
//cin>>T;
while(T--)solve();
return 0;
}
思路:分别求出差分数组,然后用KMP统计数量即可。(坑点:要用快读,不然会T)。复杂度 O ( n + m ) O(n+m) O(n+m)。
#include
#define fi first
#define se second
#define lson (k<<1)
#define rson (k<<1)+1
#define mid ((l+r)/2)
#define sz(x) int(x.size())-1
#define pii pair<int,int>
#define bit bitset<100000>
using namespace std;
const int MAX=1e6+10;
const int MOD=1e9+7;
const double PI=acos(-1.0);
typedef long long ll;
void read(int &x)
{
x=0;
int f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
x*=f;
}
int a[MAX],b[MAX],f[MAX];
int solve()
{
int m,n;
read(m);
read(n);
for(int i=1;i<=m;i++)read(a[i]);
for(int i=1;i<=n;i++)read(b[i]);
if(m==1)return printf("%d\n",n);
for(int i=0;i<=m-2;i++)a[i]=a[i+2]-a[i+1];
m--;
for(int i=0;i<=n-2;i++)b[i]=b[i+2]-b[i+1];
n--;
f[0]=f[1]=0;
for(int i=1;i<m;i++)
{
int j=f[i];
while(j&&a[i]!=a[j])j=f[j];
f[i+1]=(a[i]==a[j]?j+1:0);
}
int ans=0;
for(int i=0,j=0;i<n;i++)
{
while(j&&b[i]!=a[j])j=f[j];
if(b[i]==a[j])j++;
if(j==m)
{
ans++;
j=f[j];
}
}
return printf("%d\n",ans);
}
int main()
{
int T=1;
while(T--)solve();
return 0;
}
思路:分三种类型,求出每种类型发薪日下标区间 [ l , r ] [l,r] [l,r],并在区间端点处打上标记,利用前缀和求出累计和即可。查询时直接利用提前计算好的前缀和计算。
复杂度 O ( 10000 ∗ 366 ) O(10000*366) O(10000∗366)。
#include
#define fi first
#define se second
#define lson (k<<1)
#define rson (k<<1)+1
#define mid ((l+r)/2)
#define sz(x) int(x.size())
#define pii pair<ll,ll>
#define bit bitset<100000>
using namespace std;
const int MAX=2e5+10;
const int MOD=998244353;
const int N=3000000;
const double PI=acos(-1.0);
typedef long long ll;
int md[10000*12];
int days[12]={31,28,31,30,31,30,31,31,30,31,30,31};
struct Date{
int y,m,d;
static Date PreDay(Date d)
{
if(d.d>1){d.d--;return d;}
if(d.m>1){d.m--;d.d=Monthdays(d);return d;}
d.y--,d.m=12,d.d=31;
return d;
}
static int Monthdays(int y,int m){return days[m-1]+(m==2)*((y%4==0&&y%100!= 0)||y%400==0);}
static int Monthdays(Date d){return days[d.m-1]+(d.m==2)*((d.y%4==0&&d.y%100!= 0)||d.y%400==0);}
static int Days(Date d){return md[(d.y-2000)*12+d.m-1]+d.d;}
static int FloorWeeks(Date d){return Days(d)/7;}
static int CeilWeeks(Date d){return (Days(d)+6)/7;}
static int FloorMonths(Date d){return (d.y-2000)*12+d.m-1+(d.d>=Monthdays(d));}
static int CeilMonths(Date d){return (d.y-2000)*12+d.m;}
static int FloorHalfMonths(Date d){return ((d.y-2000)*12+d.m-1)*2+(d.d>=15)+(d.d>=Monthdays(d));}
static int CeilHalfMonths(Date d){return ((d.y-2000)*12+d.m-1)*2+1+(d.d>=16);}
};
void init()
{
memset(md,0,sizeof md);
for(int y=2000;y<=10000;y++)
for(int m=1;m<=12;m++)md[(y-2000)*12+m]=Date::Monthdays(y,m);
for(int m=1;m<=8001*12;m++)md[m]+=md[m-1];
}
ll d[3][N];
int solve()
{
auto read=[]()->Date{
char s[20];
scanf("%s",s);
if(s[0]=='N')return {9999,12,31};
return {(s[6]-'0')*1000+(s[7]-'0')*100+(s[8]-'0')*10+s[9]-'0',
(s[3]-'0')*10+s[4]-'0',
(s[0]-'0')*10+s[1]-'0'};
};
memset(d,0,sizeof d);
int n,q;
cin>>n>>q;
while(n--)
{
int money=0,be=0,ee=0,tp=0;;
scanf("%d",&money);
auto b=read();
auto e=read();
char s[20];
scanf("%s",s);
if(s[0]=='w') {
tp=0;
be=Date::CeilWeeks(b);
ee=Date::FloorWeeks(e);
} else if(s[0]=='b') {
tp=1;
be=Date::CeilHalfMonths(b);
ee=Date::FloorHalfMonths(e);
} else {
tp=2;
be=Date::CeilMonths(b);
ee=Date::FloorMonths(e);
}
d[tp][be]+=money;
d[tp][ee+1]-=money;
}
for(int i=0;i<3;i++)
for(int j=1;j<N;j++)d[i][j]+=d[i][j-1];
for(int i=0;i<3;i++)
for(int j=1;j<N;j++)d[i][j]+=d[i][j-1];
while(q--)
{
auto b=read();
auto e=read();
ll ans=0;
if(b.y==2000&&b.m==1&&b.d==1)
{
ans+=d[0][Date::FloorWeeks(e)];
ans+=d[1][Date::FloorHalfMonths(e)];
ans+=d[2][Date::FloorMonths(e)];
}
else
{
b=Date::PreDay(b);
ans+=d[0][Date::FloorWeeks(e)]-d[0][Date::FloorWeeks(b)];
ans+=d[1][Date::FloorHalfMonths(e)]-d[1][Date::FloorHalfMonths(b)];
ans+=d[2][Date::FloorMonths(e)]-d[2][Date::FloorMonths(b)];
}
printf("%lld\n",ans);
}
return 0;
}
int main()
{
init();
int T=1;
while(T--)solve();
return 0;
}
思路:求Fibonacci数列的幂次和,原题且网上有很多题解。
即利用Fibonacci的通项公式
F n = 1 5 [ ( 1 + 5 2 ) n − ( 1 − 5 2 ) n ] F_n=\frac{1}{\sqrt5}[(\frac{1+\sqrt5}{2})^n-(\frac{1-\sqrt5}{2})^n] Fn=51[(21+5)n−(21−5)n]
设 C = 1 5 , A = 1 + 5 2 , B = 1 − 5 2 C=\frac{1}{\sqrt5},A=\frac{1+\sqrt5}{2},B=\frac{1-\sqrt5}{2} C=51,A=21+5,B=21−5则
a n s = F 1 k + F 2 k + . . . + F n k = C k ( A − B ) k + C k ( A 2 − B 2 ) k + . . . + C k ( A n − B n ) k = C k ( ∑ i = 0 k ( − 1 ) i A i B k − i + ∑ i = 0 k ( − 1 ) i A 2 i B 2 ( k − i ) + . . . + ∑ i = 0 k ( − 1 ) i A n i B n ( k − i ) ) \begin{aligned} ans&=F_1^k+F_2^k+...+F_n^k\\ &=C^k(A-B)^k+C^k(A^2-B^2)^k+...+C^k(A^n-B^n)^k\\ &=C^k(\sum_{i=0}^k(-1)^iA^iB^{k-i}+\sum_{i=0}^k(-1)^iA^{2i}B^{2(k-i)}+...+\sum_{i=0}^k(-1)^iA^{ni}B^{n(k-i)}) \end{aligned} ans=F1k+F2k+...+Fnk=Ck(A−B)k+Ck(A2−B2)k+...+Ck(An−Bn)k=Ck(i=0∑k(−1)iAiBk−i+i=0∑k(−1)iA2iB2(k−i)+...+i=0∑k(−1)iAniBn(k−i))
如上式所示, ( − 1 ) i A i B k − i , ( − 1 ) i A 2 i B 2 ( k − i ) , . . . , ( − 1 ) i A n i B n ( k − i ) (-1)^iA^iB^{k-i},(-1)^iA^{2i}B^{2(k-i)},...,(-1)^iA^{ni}B^{n(k-i)} (−1)iAiBk−i,(−1)iA2iB2(k−i),...,(−1)iAniBn(k−i)构成了一个等比数列。
其中等比 q i = A i B k − i q_i=A^iB^{k-i} qi=AiBk−i,首项 a 1 = ( − 1 ) i A i B k − i a_1=(-1)^iA^iB^{k-i} a1=(−1)iAiBk−i。则
a n s = C k ∑ i = 0 k a i q i ( q i n − 1 ) q i − 1 ans=C^k\sum_{i=0}^k a_i\frac{q_i(q_i^n-1)}{q_i-1} ans=Cki=0∑kaiqi−1qi(qin−1)
接下来只需分别求出 C k , A i , B k − i 对 1 0 9 + 7 C^k,A^i,B^{k-i}对10^9+7 Ck,Ai,Bk−i对109+7取模后的值,然后用于计算即可。
A , B , C A,B,C A,B,C均带有 5 \sqrt{5} 5,如果 5 5 5是 1 0 9 + 7 10^9+7 109+7的二次剩余,则我们求出平方同于 5 5 5的整数解,用来代替 5 \sqrt{5} 5计算即可。但 5 5 5不是 1 0 9 + 7 10^9+7 109+7的二次剩余。
考虑利用复数的性质将 A , B , C A,B,C A,B,C转化为复数的形式来计算,其中虚部带根号,实部不带根号。即
A = 1 2 + 1 2 i B = 1 2 − 1 2 i C = 1 2 i \begin{aligned} A&=\frac12+\frac12i\\ B&=\frac12-\frac12i\\ C&=\frac12i \end{aligned} ABC=21+21i=21−21i=21i
其中 i = 5 , i 2 = 5 i=\sqrt{5},i^2=5 i=5,i2=5。
因为最终答案一定是整数,所以只需输出最终虚数的实部即可。
复杂度 O ( k ∗ log 2 n ) O(k*\log_2n) O(k∗log2n)。
#include
#define fi first
#define se second
#define lson (k<<1)
#define rson (k<<1)+1
#define mid ((l+r)/2)
#define sz(x) int(x.size())
#define pii pair<ll,ll>
#define bit bitset<100000>
using namespace std;
const int MAX=2e6+10;
const int MOD=1e9+7;
const double PI=acos(-1.0);
typedef long long ll;
ll Inv(ll x) {
ll ret=1;
for(int n=MOD-2;n;n>>=1){
if(n&1)ret=ret*x%MOD;
x=x*x%MOD;
}return ret;
}
struct Complex
{
ll x,y;
Complex(ll _x=0,ll _y=0) {
x=_x%MOD,y=_y%MOD;
if(x<0)x+=MOD;
if(y<0)y+=MOD;
}
bool operator==(const Complex &q){return x==q.x&&y==q.y;}
Complex operator+(const Complex &q){return {x+q.x,y+q.y};}
Complex operator-(const Complex &q){return {x-q.x,y-q.y};}
Complex operator*(const Complex &q){return {x*q.x+y*q.y*5,x*q.y+y*q.x};}
Complex operator/(const Complex &d) {
ll _d=(d.x*d.x-5*d.y*d.y)%MOD+MOD;
ll _x=(x*d.x-5*y*d.y)%MOD+MOD;
ll _y=(y*d.x-x*d.y)%MOD+MOD;
return {_x*Inv(_d),_y*Inv(_d)};
}
};
Complex POW(Complex _x, ll n) {
Complex ret=1;
for(;n;n>>=1){
if(n&1)ret=ret*_x;
_x=_x*_x;
}return ret;
}
ll fac[MAX],inv[MAX];
ll C(ll n,ll m){return fac[n]*inv[n-m]%MOD*inv[m]%MOD;}
int solve()
{
ll n,k;
cin>>n>>k;
fac[0]=inv[0]=inv[1]=1;
for(int i=1;i<=k;i++)fac[i]=fac[i-1]*i%MOD;
for(int i=2;i<=k;i++)inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=k;i++)inv[i]=inv[i]*inv[i-1]%MOD;
Complex A=Complex(1,1)/2;
Complex B=Complex(1,-1)/2;
Complex ans=0;
for(ll i=0;i<=k;i++)
{
Complex q=POW(A,k-i)*POW(B,i);
Complex a1=q;
Complex s=0;
if(q==1)s=a1*(n%MOD);
else s=a1*(POW(q,n)-1)/(q-1);
if(i%2)ans=ans-s*C(k,i);
else ans=ans+s*C(k,i);
}
ans=ans/POW(Complex(0,1),k);
cout<<ans.x<<endl;
return 0;
}
int main()
{
int T=1;
//cin>>T;
while(T--)solve();
return 0;
}
思路:用 i n [ i ] in[i] in[i]和 o u t [ i ] out[i] out[i]分别记录点 i i i的入度和出度。
每新增一条边 u , v u,v u,v,则总路径数增加 i n [ u ] + o u t [ v ] + [ u = = v ] in[u]+out[v]+[u==v] in[u]+out[v]+[u==v]。
每一分钟可能增加的最大路径数为 i n i + o u t i + 1 in_i+out_i+1 ini+outi+1(增加边 i , i i,i i,i)或 max ( i n i ) + max ( o u t j ) \max(in_i)+\max(out_j) max(ini)+max(outj)(增加边 i , j i,j i,j)。
复杂度 O ( t ) O(t) O(t)。
#include
#define fi first
#define se second
#define lson (k<<1)
#define rson (k<<1)+1
#define mid ((l+r)/2)
#define sz(x) int(x.size())
#define pii pair<ll,ll>
#define bit bitset<100000>
using namespace std;
const int MAX=1e5+10;
const int MOD=998244353;
const double PI=acos(-1.0);
typedef long long ll;
ll in[MAX],out[MAX];
int solve()
{
memset(in,0,sizeof in);
memset(out,0,sizeof out);
ll maxout=0,maxin=0,ans=0,em=0;
int n,q;
cin>>n>>q;
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
ans+=in[x]+out[y]+(x==y);
printf("%lld ",ans);
out[x]++;
in[y]++;
maxout=max(maxout,out[x]);
maxin=max(maxin,in[y]);
em=max(em,in[x]+out[x]+1);
em=max(em,in[y]+out[y]+1);
printf("%lld\n",max(maxin+maxout,em));
}
return 0;
}
int main()
{
int T=1;
while(T--)solve();
return 0;
}
思路:统计点 k k k到根路径上出现的不同数的个数, d f s dfs dfs即可。
复杂度 O ( n ) O(n) O(n)。
#include
#define fi first
#define se second
#define lson (k<<1)
#define rson (k<<1)+1
#define mid ((l+r)/2)
#define sz(x) int(x.size())-1
#define pii pair<int,int>
#define bit bitset<100000>
using namespace std;
const int MAX=1e6+10;
const int MOD=1e9+7;
const double PI=acos(-1.0);
typedef long long ll;
vector<int>e[MAX];
int g[MAX],c[MAX],ans[MAX];
void dfs(int k,int a)
{
c[g[k]]++;
a+=(c[g[k]]==1);
ans[k]=a;
for(int i:e[k])dfs(i,a);
c[g[k]]--;
}
int solve()
{
memset(c,0,sizeof c);
int n,root;
cin>>n;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
if(x)e[x].push_back(i);
else root=i;
}
for(int i=1;i<=n;i++)scanf("%d",g+i);
dfs(root,0);
for(int i=1;i<=n;i++)printf("%d ",ans[i]);
return 0;
}
int main()
{
int T=1;
while(T--)solve();
return 0;
}
思路:比下大小即可。
#include
#define fi first
#define se second
#define lson (k<<1)
#define rson (k<<1)+1
#define mid ((l+r)/2)
#define sz(x) int(x.size())
#define pii pair<ll,ll>
#define bit bitset<100000>
using namespace std;
const int MAX=1e3+10;
const int MOD=998244353;
const double PI=acos(-1.0);
typedef long long ll;
int solve()
{
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
return puts(n/k>=m?"Iron fist Ketil":"King Canute");
}
int main()
{
int T=1;
// cin>>T;
while(T--)solve();
return 0;
}
思路:如果2点间存在一条经过环的路径或者这2点本身就在环上,则这2点间的路径就不唯一,因为经过环则至少有2条路径。
那么接下来只要用拓扑排序删除图中的环,得到一个个联通块,然后再 d f s dfs dfs将联通块里的点用并查集合并即可。
复杂度 O ( n ) O(n) O(n)。
#include
#define fi first
#define se second
#define lson (k<<1)
#define rson (k<<1)+1
#define mid ((l+r)/2)
#define sz(x) int(x.size())
#define pii pair<int,int>
#define bit bitset<100000>
using namespace std;
const int MAX=1e5+10;
const int MOD=998244353;
const double PI=acos(-1.0);
typedef long long ll;
vector<pii>e[MAX];
int d[MAX],p[MAX],v[MAX];
int f(int x){return x==p[x]?x:p[x]=f(p[x]);}
void dfs(int k)
{
if(d[k]>=2)return;
for(auto &kv:e[k])
{
if(d[kv.fi]>=2||f(k)==f(kv.fi))continue;
p[f(k)]=f(kv.fi);
dfs(kv.fi);
}
}
int solve()
{
memset(d,0,sizeof d);
memset(v,0,sizeof v);
int n,m,t;
cin>>n>>m>>t;
for(int i=1;i<=n;i++)p[i]=i;
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
e[x].push_back({y,i});
e[y].push_back({x,i});
d[x]++;
d[y]++;
}
queue<int>q;
for(int i=1;i<=n;i++)if(d[i]==1)q.push(i);
while(!q.empty())
{
int x=q.front();q.pop();
for(auto &kv:e[x])
{
if(v[kv.se])continue;
v[kv.se]=1;
d[kv.fi]--;
if(d[kv.fi]<=1)q.push(kv.fi);
}
}
for(int i=1;i<=n;i++)dfs(i);
while(t--)
{
int x,y;
scanf("%d%d",&x,&y);
puts(f(x)==f(y)?"YES":"NO");
}
return 0;
}
int main()
{
int T=1;
while(T--)solve();
return 0;
}
思路:按题意循环统计即可。复杂度 O ( n 2 ) O(n^2) O(n2)。
#include
#define fi first
#define se second
#define lson (k<<1)
#define rson (k<<1)+1
#define mid ((l+r)/2)
#define sz(x) int(x.size())
#define pii pair<ll,ll>
#define bit bitset<100000>
using namespace std;
const int MAX=1e3+10;
const int MOD=998244353;
const double PI=acos(-1.0);
typedef long long ll;
int a[MAX][MAX];
int solve()
{
int n,k,ans=0;
cin>>n>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)scanf("%d",&a[i][j]);
for(int i=1;i+k-1<=n;i++)
for(int j=1;j+k-1<=n;j++)
{
ans+=(a[i][j]==a[i+k-1][j]&&a[i][j]==a[i][j+k-1]&&a[i][j]==a[i+k-1][j+k-1]);
}
return printf("%d\n",ans);
}
int main()
{
int T=1;
// cin>>T;
while(T--)solve();
return 0;
}
思路:考虑二分答案 t ( t ≤ 500 ) t(t\le500) t(t≤500),那么 A , B , C 三人拥有的做题时间分别为 A ∗ t , B ∗ t , C ∗ t A,B,C三人拥有的做题时间分别为A*t,B*t,C*t A,B,C三人拥有的做题时间分别为A∗t,B∗t,C∗t,然后用背包算法将 n n n个题目依次配给三人,若题目能分配完则满足条件。
复杂度 O ( n ∗ 5000 ∗ log 2 500 ) O(n*5000*\log_2500) O(n∗5000∗log2500)。
#include
#define fi first
#define se second
#define lson (k<<1)
#define rson (k<<1)+1
#define mid ((l+r)/2)
#define sz(x) int(x.size())-1
#define pii pair<int,int>
#define bit bitset<100000>
using namespace std;
const int MAX=1e5+10;
const int MOD=998244353;
const double PI=acos(-1.0);
typedef long long ll;
int a,b,c,t[51];
int d[51][5001];
int f(int n,int x)
{
vector<int>v;
v.push_back(0);
for(int i=1;i<=n;i++)v.push_back(t[i]);
auto cal=[&](int speed) {
memset(d,0,sizeof d);
d[0][0]=1;
for(int i=1;i<=sz(v);i++)
for(int j=x*speed;j>=0;j--)
{
if(j>=v[i])d[i][j]|=d[i-1][j-v[i]];
d[i][j]|=d[i-1][j];
}
int ma=-1;
for(int i=0;i<=x*speed;i++)if(d[sz(v)][i])ma=i;
for(int i=sz(v);i>=1;i--)
{
if(ma>=v[i]&&d[i][ma]&&d[i-1][ma-v[i]])
{
ma-=v[i];
v.erase(v.begin()+i);
}
}
};
cal(c);
cal(b);
cal(a);
return sz(v)<=0;
}
int solve()
{
int n;
cin>>n>>a>>b>>c;
for(int i=1;i<=n;i++)scanf("%d",t+i);
int l=1,r=500,ans=0;
while(r>=l)
{
if(f(n,mid))ans=mid,r=mid-1;
else l=mid+1;
}
cout<<ans<<endl;
return 0;
}
int main()
{
int T=1;
while(T--)solve();
return 0;
}
思路: d [ i ] d[i] d[i]表示在执行了若干操作后以 a i a_i ai结尾的不同数组的数量,则 d [ j ] + = d [ i ] ( i < j 且 a j = min ( a k ) i < k ≤ j ) d[j]+=d[i](i
#include
#define fi first
#define se second
#define lson (k<<1)
#define rson (k<<1)+1
#define mid ((l+r)/2)
#define sz(x) int(x.size())
#define pii pair<ll,ll>
#define bit bitset<100000>
using namespace std;
const int MAX=5e3+10;
const int MOD=998244353;
const double PI=acos(-1.0);
typedef long long ll;
int a[MAX],d[MAX];
int solve()
{
int n;
cin>>n;
memset(d,0,sizeof d);
d[0]=1,a[0]=n+1;
for(int i=1;i<=n;i++)scanf("%d",a+i);
for(int i=1;i<=n;i++)
for(int j=i-1,x=n+1;j>=0;j--)
{
if(min(a[j],a[i])<x)(d[i]+=d[j])%=MOD;
x=min(x,a[j]);
}
int x=n+1,ans=0;
for(int i=n;i>=1;i--)
{
if(x>a[i])(ans+=d[i])%=MOD;
x=min(x,a[i]);
}
cout<<ans<<endl;
return 0;
}
int main()
{
int T=1;
//cin>>T;
while(T--)solve();
return 0;
}
思路:用 d [ i ] [ k ] d[i][k] d[i][k]表示采集 [ i , i + k − 1 ] [i,i+k-1] [i,i+k−1]区间内珍珠可以获得的最大点数,当 d [ i ] [ k ] ≥ 0 d[i][k]\ge 0 d[i][k]≥0时,则可以更新答案。转移如下:
d [ i ] [ k ] = max ( d [ i ] [ k − 1 ] + a i + k − 1 , d [ i + 1 ] [ k − 1 ] + a k ) d[i][k]=\max(d[i][k-1]+a_{i+k-1},d[i+1][k-1]+a_k) d[i][k]=max(d[i][k−1]+ai+k−1,d[i+1][k−1]+ak)复杂度 O ( n ∗ k ) O(n*k) O(n∗k)。
#include
#define fi first
#define se second
#define lson (k<<1)
#define rson (k<<1)+1
#define mid ((l+r)/2)
#define sz(x) int(x.size())
#define pii pair<ll,ll>
#define bit bitset<100000>
using namespace std;
const int MAX=1e5+101;
const int MOD=998244353;
const double PI=acos(-1.0);
typedef long long ll;
ll a[MAX],d[MAX][101];
int solve()
{
int n,k;
cin>>n>>k;
k=min(k,n);
for(int i=1;i<=n;i++)scanf("%lld",a+i);
memset(d,-1,sizeof d);
for(int i=1,x;i<=n;i++)
{
scanf("%d",&x);
a[i]=(x==1?a[i]:-a[i]);
d[i][1]=a[i];
}
for(int i=n+1;i<=n+k-1;i++)
{
a[i]=a[i-n];
d[i][1]=d[i-n][1];
}
ll ans=0;
for(int i=2;i<=k;i++)
{
ll sum=0;
for(int j=1;j<=i;j++)sum+=max(0ll,-a[j]);
for(int j=1;j<=n;j++)
{
if(d[j][i-1]>=0)d[j][i]=max(d[j][i],d[j][i-1]+a[j+i-1]);
if(d[j+1][i-1]>=0)d[j][i]=max(d[j][i],d[j+1][i-1]+a[j]);
if(d[j][i]>=0)ans=max(ans,sum);
sum+=max(0ll,-a[j+i]);
sum-=max(0ll,-a[j]);
}
for(int j=n+1;j<=n+k-1;j++)d[j][i]=d[j-n][i];
}
cout<<ans<<endl;
return 0;
}
int main()
{
int T=1;
//cin>>T;
while(T--)solve();
return 0;
}