比赛时一直以为是个组合数找规律的题,今天一想应该要用dp,推了一节毛概课,到晚上终于给A了。
dp[i][j]表示当第i轮有j个不同的时的方案数,那么可以得到初始条件dp[0][num]=1(num表示一开始有多少个灯状态不同,因为接下来递推要用乘法所以初始化为1,这里只需知道dp[0][num]是初始条件即可)
那么dp[i][j]可以怎么得到呢?
首先肯定是从第i-1轮得到,这时假设第i-1轮有p个灯的状态不同,第i轮要有j个灯的状态不同,那么怎么从p到j呢?
可以从p中选择x个变换,从n-p(即相同状态的灯)中选择y个变换,当然x,y不能随便选,因为一轮要变换k个,所以首先x+y==m,还有从p个不同的状态到j个不同的状态还要满足p-x+y==j,
这时列一个二元一次方程组,即可得到y=(j+m-p)/2,这时还要满足y是整数。所以x为 m-y。
所以可以得出状态转移方程 dp[i][j]+=(dp[i-1][p]*C(p,x)%mod*C(n-p,y)%mod)%mod.
求组合数要用杨辉三角求,,否则会超时。。。
还要注意所有地方都要注意取模
#include<bits/stdc++.h>
#define exp 1e-8
#define mian main
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ll long long
#define pb push_back
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
#define w(x) while(x--)
#define int_max 2147483647
#define lowbit(x) (x)&(-x)
#define gcd(a,b) __gcd(a,b)
#define pq(x) priority_queue<x>
#define ull unsigned long long
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define pl(a,n) next_permutation(a,a+n)
#define ios ios::sync_with_stdio(false)
#define met(a,x) memset((a),(x),sizeof((a)))
using namespace std;
const int N=110;
const int mod=998244353;
ll dp[N][N]; //dp[i][j] 第i轮有j个不同时的方案数
char a[N],b[N];
int n,m,k;
ll c[N][N];
void init()
{
c[1][1]=1;
c[0][0]=1;
c[1][0]=1;
for(int i=2;i<=110;i++){
c[i][0]=1;
for(int j=1;j<=i;j++)
c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
}
int main()
{
int t;
scanf("%d",&t);
init();
while(t--){
scanf("%d%d%d",&n,&k,&m);
scanf("%s%s",&a,&b);
int num=0;
for(int i=0;i<n;i++)
if(a[i]!=b[i])
num++;
met(dp,0);
dp[0][num]=1;// 初始化
for(int i=1;i<=k;i++){
for(int j=0;j<=n;j++){
for(int p=0;p<=n;p++){ //上一轮有p个不同
if(j+m-p<0)
break;
if((j+m-p)%2)
continue;
int y=(j+m-p)/2; //要满足的条件
int x=m-y; //从p中拿x个,n-p中拿y个
if(x>p||y>n-p||x<0)
continue;
dp[i][j]+=(dp[i-1][p]*c[p][x]%mod*c[n-p][y]%mod)%mod;
dp[i][j]%=mod;
}
}
}
printf("%lld\n",dp[k][0]%mod);
}
}
这时n三次方的复杂度即可过。
暴力贪心,比赛时没想到这么贪也能过,以为会T......就没有写
应该是没有给特别大的数据,正解应该用到了优先队列优化成nlogn。
#include<bits/stdc++.h>
#define exp 1e-8
#define mian main
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ll long long
#define pb push_back
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
#define w(x) while(x--)
#define int_max 2147483647
#define lowbit(x) (x)&(-x)
#define gcd(a,b) __gcd(a,b)
#define pq(x) priority_queue<x>
#define ull unsigned long long
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define pl(a,n) next_permutation(a,a+n)
#define ios ios::sync_with_stdio(false)
#define met(a,x) memset((a),(x),sizeof((a)))
using namespace std;
const int N=1e5+10;
int n,ans;
struct node
{
int l,r;
}a[N];
bool cmp(node x,node y)
{
if(x.l==y.l)
return x.r<y.r;
return x.l<y.l;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&a[i].l,&a[i].r);
sort(a+1,a+1+n,cmp);
map<int,int>mp;
mp.clear();
ans=0;
for(int i=n;i>=1;i--){
for(int j=a[i].r;j>=a[i].l;j--){
if(mp[j]==0){
mp[j]=1;
ans++;
break;
}
}
}
printf("%d\n",ans);
}
}
思路:
当输入的两个点相等时,全输出0,当有环的时候也输出全是0
拓扑排序判环,在对于每一个点正向搜索小于它的点,反向搜大于它的点,对于这些点只要满足num1[i]<=n/2 &&num2[i]<=n/2, 即可,对于不同连通图中的点不需要考虑
#include<bits/stdc++.h>
#define exp 1e-8
#define mian main
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ll long long
#define pb push_back
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
#define w(x) while(x--)
#define int_max 2147483647
#define lowbit(x) (x)&(-x)
#define gcd(a,b) __gcd(a,b)
#define pq(x) priority_queue<x>
#define ull unsigned long long
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define pl(a,n) next_permutation(a,a+n)
#define ios ios::sync_with_stdio(false)
#define met(a,x) memset((a),(x),sizeof((a)))
using namespace std;
const int N=110;
int head[N],rhead[N];
int num1[N],num2[N];
int in1[N];
int n,m,tot1,tot2;
bool vis[N];
struct node
{
int ne,v;
}e[N*N],re[N*N];
bool tuopu()//еп╩╥
{
queue<int>q;
for(int i=1;i<=n;i++)
if(in1[i]==0)
q.push(i);
int cnt=0;
while(!q.empty()){
int u=q.front();
q.pop();
cnt++;
for(int i=head[u];i;i=e[i].ne){
int v=e[i].v;
in1[v]--;
if(in1[v]==0)
q.push(v);
}
}
return cnt==n;
}
void bfs2()
{
queue<int>que;
for(int i=1;i<=n;i++){
met(vis,0);
que.push(i);
int ans=0;
while(!que.empty()){
int u=que.front();
que.pop();
for(int j=head[u];j;j=e[j].ne){
int x=e[j].v;
if(vis[x])
continue;
ans++;
que.push(x);
vis[x]=1;
}
}
num1[i]=ans;
}
}
void bfs()
{
queue<int>que;
for(int i=1;i<=n;i++){
met(vis,0);
que.push(i);
int ans=0;
while(!que.empty()){
int u=que.front();
que.pop();
for(int j=rhead[u];j;j=re[j].ne){
int x=re[j].v;
if(vis[x])
continue;
ans++;
que.push(x);
vis[x]=1;
}
}
num2[i]=ans;
}
}
void add1(int x,int y)
{
e[++tot1].ne=head[x];
e[tot1].v=y;
head[x]=tot1;
}
void add2(int x,int y)
{
re[++tot2].ne=rhead[x];
re[tot2].v=y;
rhead[x]=tot2;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
int x,y;
scanf("%d%d",&n,&m);
tot1=0;
tot2=0;
for(int i=0;i<=n;i++){
num1[i]=0;
num2[i]=0;
head[i]=0;
rhead[i]=0;
in1[i]=0;
}
bool flag=false;
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
if(x==y)
flag=true;
add1(x,y);
add2(y,x);
in1[y]++;
}
if(flag){
for(int i=1;i<=n;i++)
printf("0");
printf("\n");
continue;
}
if(tuopu()){
bfs2();
bfs();
for(int i=1;i<=n;i++){
if(num1[i]<=n/2&&num2[i]<=n/2)
printf("1");
else printf("0");
}
printf("\n");
}
else {
for(int i=1;i<=n;i++)
printf("0");
printf("\n");
}
}
}