簽到題
int T;
ll x,y,a,b;
int main() {
qr(T);while(T--) {
qr(x); qr(y); qr(a); qr(b);
if(x>y) swap(x,y);
if(a*2>b) pr2(b*x+(y-x)*a);
else pr2((x+y)*a);
}
return 0;
}
這麼簡單比賽的時候竟沒想出來
簡明題意:
給定一個01串,求有個子序列正好爲的01串,同時滿足的最小正週期最小.
顯然,所有數都相同時輸出讀入的即可.
否則,可以用個01來輸出.(顯然一定滿足條件)
int T,n;
char s[N];
int main() {
qr(T); while(T--) {
scanf("%s",s+1); n=strlen(s+1);
bool same=1;
for(int i=2;s[i];i++) if(s[i]!=s[1]) {same=0;break;}
if(same) puts(s+1);
else {for(int i=1;i<=2*n;i++) putchar((i&1)+'0'); puts("");}
}
return 0;
}
找循環節即可.
int T,a,b,q,s[N],n;
ll f(ll x) {return 1LL*(x/n)*s[n]+s[x%n];}
int main() {
qr(T); while(T--) {
qr(a); qr(b); qr(q);
n=a*b;
for(int i=1;i<=n;i++) s[i]=((i%a)%b!=(i%b)%a)+s[i-1];
while(q--) {
ll l,r; qr(l); qr(r);
pr1(f(r)-f(l-1));
}
puts("");
}
return 0;
}
貪心.
從後往前選更容易判斷是否合法.
我們貪心維護一個|testdata|不嚴格下降序列,在不得不擴容時擴容即可.
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=2e5+10;
struct edge{int y,next;}e[N<<1]; int len,last[N],cnt[N];
void ins(int x,int y) {e[++len]=(edge){y,last[x]};last[x]=len;cnt[x]++;}
int n,m,a[N],c[N],t,ans;
int main() {
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&t),a[t]++;
for(int i=1;i<=m;i++) scanf("%d",&c[i]);
for(int i=m; i;i--) {//存儲大小滿足不嚴格下降
n=0;
for(int j=(1<<17);j>=1;j/=2)
if(cnt[n+j]==c[i]) n+=j;
for(int j=a[i];j--; ins(n,i))
while(cnt[n]==c[i]) n++;
ans=max(ans,n);
}
printf("%d\n",ans+1);
for(int i=0;i<=ans;i++) {
printf("%d",cnt[i]);
for(int k=last[i];k;k=e[k].next)
printf(" %d",e[k].y);
puts("");
}
return 0;
}
容斥原理(或者是第二類斯特林數(還沒學,之後要補))
題意:
,已知,要使得每個格子都能被車攻擊且車之間兩兩能攻擊的情況正好爲個.(中間不能有其他的車)求總方案個數.
顯然,車要麼排滿行,要麼排滿列.
這兩種情況顯然是可以一一對應的,所以我們僅求一個即可.
考慮每一列都排滿,那麼有車的行顯然有個.
開始容斥:
設.
意思:行任選爲,顯然這樣有空行,所以要-…
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=2e5+20,mod=998244353;
ll n,m,q,jc[N],inv[N],ans,f;
ll power(ll a,ll b=mod-2) {
ll c=1;
while(b) {
if(b&1) c=c*a%mod;
a=a*a%mod; b=b>>1;
}
return c;
}
ll C(ll x,ll y){return jc[x]*inv[y]%mod*inv[x-y]%mod;}
int main() {
scanf("%lld%lld",&n,&m);
if(m>=n) puts("0");
else {
jc[0]=1;for(int i=1;i<=n;i++) jc[i]=jc[i-1]*i%mod;
if(!m) return printf("%lld\n",jc[n]),0;
inv[n]=power(jc[n]);for(int i=n;i;i--) inv[i-1]=inv[i]*i%mod;
f=1;q=n-m;
for(int i=q;i>0;i--) {
ans+=f*power(i,n)*C(q,q-i)%mod;
f=-f;
}
ans=(ans%mod+mod)%mod;
printf("%lld\n",ans*2*C(n,m)%mod);
}
return 0;
}
狀壓DP.
單組數據複雜度.
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=18,M=1<<15|10;
struct node {
int x,y,tx,ty;
//操作數,末尾數,轉移函數
node(int x=M,int y=0,int tx=0,int ty=0):x(x),y(y),tx(tx),ty(ty){};
bool operator <(node b) const {
return x!=b.x?x<b.x:y<b.y;
}
node get(int a,int b,int c,int d) {
return {x+a,b,c,d};
}
}f[N][M],ans[N];
int T,n,m,a[N],sum[M],cnt[M],lg[M],tot;
int main() {
scanf("%d",&T);
for(int i=1;i<M;i++) cnt[i]=cnt[i&(i-1)]+1;
for(int i=0;i<15;i++) lg[1<<i]=i;
while(T--) {
scanf("%d",&n);m=1<<n;
for(int i=0;i<n;i++) scanf("%d",&a[i]);
for(int i=1;i<m;i++) sum[i]=sum[i&(i-1)]+a[lg[i&(-i)]];
for(int i=0;i<=n;i++) for(int j=0;j<m;j++) f[i][j]=node();
f[0][m-1]=node(0);
for(int i=1;i<=n;i++)
for(int j=0;j<m;j++) if(f[i-1][j].x^M) {//上一個狀態
f[i][j]=min(f[i][j],f[i-1][j]);
if(j>>(i-1)&1) {
int mask=j^(1<<(i-1));
for(int s=mask; ;s=(s-1)&mask) {
int t=s|(1<<(i-1));//當前選擇
if(f[i-1][j].y<sum[t])//上升
f[i][j^t]=min(f[i][j^t],f[i-1][j].get(cnt[s],sum[t],i-1,j));
if(!s) break;
}
}
}
printf("%d\n",f[n][0].x); tot=0;
for(int i=n,j=0;j^(m-1); ) {
int x=f[i][j].tx,y=f[i][j].ty,t=j^y^(1<<x);
for(int k=0;k<n;k++) if(t>>k&1) ans[++tot]=node(k,x);
i=x; j=y;
}
for(int i=1;i<=tot;i++) {
int x=ans[i].x,y=ans[i].y;
printf("%d %d\n",x+1,y+1);
for(int k=i+1;k<=tot;k++)
ans[k].x-=(ans[k].x>x),
ans[k].y-=(ans[k].y>x);
}
}
return 0;
}