題意:拼圖,每塊拼圖部件有一個凹三個凸,只有凹凸可以貼合.問能否拼成的圖.
每個點有1個出度,3個入度.(邊界的點看作對外有出度)
那麼 一定可以.
而,由樣例得可行.
對於其他情況一定包含一個的矩陣.
而這個矩陣內有7個相接的地方,由於每個相接的地方都有有凹,但實際上6<7,所以無論如何都不行.
int T,n,m;
int main() {
qr(T); while(T--) {
qr(n); qr(m);
if(n==m&&n==2) puts("yes");
else if(min(n,m)==1) puts("yes");
else puts("no");
}
return 0;
}
容易看出一個DP轉移函數:
表示高度爲要多少張牌.
打表找到上界,然後每次用二分來查數即可.
int T,n,ans;
ll f[N];
void dfs(int x) {
while(x>=2) {
x-=(*(upper_bound(f+1,f+N,x)-1));
ans++;
}
}
int main() {
f[1]=2;for(int i=2;i<N;i++) f[i]=2*f[i-1]-f[i-2]+3;
qr(T);while(T--) {
ans=0; qr(n);
dfs(n); pr2(ans);
}
return 0;
}
更快的做法:
可以發現
解方程即可.
一開始題目看不懂,QAQ…
題意:給你個整數,判斷是否不存在 .
首先對於一個同餘系的數一定不會衝突.
然後我們枚舉,判斷是否
開個bool數組判斷是否互不相同即可.
int T,n,a[N],ans,vis[N],num;
int main() {
qr(T); while(T--) {
qr(n);for(int i=0;i<n;i++) qr(a[i]);
ans=0; num++;
for(int i=0,x;i<n;i++) {
x=(i+a[i]%n+n)%n;
if(vis[x]==num) {puts("No");ans=1;break;}
else vis[x]=num;
}
if(!ans) puts("YES");
}
return 0;
}
題意:
給定的顏色(黑白)矩陣.開始隨意放置S/N極.
之後當一對S,N極共享一個行/列,且不在同一個位置時,N往S靠近一個單位.
這個初始放置必須在隨意移動後滿足:
- S極出現在每一行,每一列.
- N極可以到達所有的黑格.
- N極無法到達所有的白格.
求初始放置的最少N極數.
引理:
- 每行/列只能有一段黑.
- 一行無黑必須保證有列也無黑.
判定完不合法的情況後,只需計算黑色連通塊數即可.
int n,m,v[N][N],cnt;
bool r[N],c[N];
char s[N][N];
void out(){puts("-1"),exit(0);}
const int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
void dfs(int x,int y) {
v[x][y]=cnt;
for(int t=0;t<4;t++) {
int tx=x+dx[t],ty=y+dy[t];
if(s[tx][ty]=='#'&&!v[tx][ty]) dfs(tx,ty);
}
}
int main() {
qr(n);qr(m);
//每行/列至多有一段黑.
for(int i=1;i<=n;i++) {
scanf("%s",s[i]+1);
for(int j=1,k=0;j<=m;j++)
if(s[i][j]=='#') {
r[i]=c[j]=1;
if(s[i][j]!=s[i][j-1]) {
if(++k>=2) out();
}
}
}
for(int j=1;j<=m;j++)
for(int i=1,k=0;i<=n;i++)
if(s[i][j]=='#') {
r[i]=c[j]=1;
if(s[i][j]!=s[i-1][j]) {
if(++k>=2) out();
}
}
//每行每列都要有S極
int a=0,b=0;
for(int i=1;i<=n;i++) a+=!r[i];
for(int j=1;j<=m;j++) b+=!c[j];
if(a^b&&(!a||!b)) out();
//接下來,每個黑色連通塊都放一個N極.
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) if(s[i][j]=='#'&&!v[i][j]) cnt++,dfs(i,j);
pr2(cnt);
return 0;
}
實際可用並查集來合併行列(因爲每行/列至多有一段).
題目好繞,對我很不友好.
最後,求滿足條件的最多的數量
我們把相互關係看作,即一條有向邊.
則顯然,如果成環則無論如何都不合法,輸出
然後,任意兩個有大小關係的數至多有一個.
所以我們用拓撲判環+正反向DP即可.
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define gc getchar()
using namespace std;
const int N=2e5+10;
void qr(int &x) {
char c=gc; x=0;
while(!isdigit(c))c=gc;
while(isdigit(c))x=x*10+c-'0',c=gc;
}
int n,m,f[N],g[N],ans,q[N];
struct edge{int y,next;}a[N]; int len,last[N],deg[N];
void ins(int x,int y) {a[++len]=(edge){y,last[x]};last[x]=len;deg[y]++;}
void topsort() {
int l=1,r=0;
for(int i=1;i<=n;i++) if(!deg[i]) q[++r]=i;
while(l<=r) {
int x=q[l++];
for(int k=last[x],y;k;k=a[k].next) {
y=a[k].y;
f[y]=min(f[x],f[y]);
if(!(--deg[y])) q[++r]=y;
}
}
if(r<n) puts("-1"),exit(0);
while(r) {
int x=q[r--];
for(int k=last[x],y;k;k=a[k].next) {
y=a[k].y;
g[x]=min(g[x],g[y]);
}
}
}
int main() {
qr(n); qr(m);
for(int i=1;i<=n;i++) f[i]=g[i]=i;
for(int i=1,x,y;i<=m;i++) {
qr(x),qr(y);
ins(x,y);
}
topsort();
for(int i=1;i<=n;i++) f[i]=min(f[i],g[i]),ans+=(f[i]==i);
printf("%d\n",ans);
for(int i=1;i<=n;i++) putchar("EA"[f[i]==i]);
return 0;
}
//有環一定不合法.
//然後對於任意有大小關係的變量之間只能有一個forall.
//於是,對每個點求跟其大小相關的點的最小值.
//做法:用拓撲排序判環/正反向DP.
定義二元函數
我們考慮增量法:把x-1弄到x->.
顯然這是一個當時遞減的函數.
一個貪心的做法是每次取最大的變化量,複雜度,配合堆優化可
但是k太大了,不能直接處理.
我們要利用到增量的遞減性質.
由貪心思路得:每次選擇的變化量不嚴格遞減.
所以,如果我們確定最後一個變化量,即可求出最多變化多少次.這個考慮二分處理:
最後還剩下至多個數可選擇,對還能選擇的量進行排序貪心選大的即可.
ps:對於每個,求最多增加幾次的時候可二分可用解二次方程的方法
複雜度:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<functional>
#define pi pair<ll,int>
#define ll long long
using namespace std;
const int N=1e5+10;
int n,b[N];
ll m,a[N],tot;
pi s[N];int cnt;
ll f(ll x,ll y) {return y-1-3*x*(x-1);}
int calc(ll x,ll t) {//x爲a[i],t爲delta的下界 .找第一個<t的位置
int l=1,r=x+1,mid;
while(l<r) {
mid=l+r>>1;
if(f(mid,x)<t) r=mid;
else l=mid+1;
}
return l-1;
}
bool check(ll x) {
tot=0;
for(int i=1;i<=n&&tot<=m;i++) tot+=(b[i]=calc(a[i],x));
return tot<=m;
}
int main() {
scanf("%d %lld",&n,&m);
ll l=9e18,r=0,mid;
for(int i=1;i<=n;i++) scanf("%lld",&a[i]),r=max(r,f(1,a[i])),l=min(l,f(a[i],a[i]));
while(l<r) {
mid=l+r>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
check(l);
m=m-tot;
if(m) for(int i=1;i<=n;i++)
if(b[i]<a[i])
s[++cnt]=make_pair(f(b[i]+1,a[i]),i);
sort(s+1,s+cnt+1,greater<pi>());
for(int i=1;i<=m;i++) b[s[i].second]++;
for(int i=1;i<=n;i++) printf("%d ",b[i]);
return 0;
}