取一定能構成
int a,b,c,d,T;
int main() {
qr(T); while(T--) {
qr(a); qr(b); qr(c); qr(d);
pr1(b); pr1(c); pr2(c);
}
return 0;
}
暴力用操作1,再用操作2.
注意操作1不要增即可.
int T,x,n,m;
int main() {
qr(T); while(T--) {
qr(x); qr(n); qr(m);
while(n&&x>(x/2)+10) n--,x=x/2+10;
if(m*10>=x) puts("YES");
else puts("NO");
}
return 0;
}
最優情況下,一個點被設爲工業城市當且僅當子樹內所有點都爲工業城市.(微擾證明(交換))
所以用堆存即可.
考試的時候想到了,但是不知道爲啥打掛了(WA#6)
priority_queue<int>q;
int n,m,fa[N],dep[N],sz[N];
ll ans;
struct edge{int y,next;}a[N<<1]; int len,last[N];
void ins(int x,int y) {a[++len]=(edge){y,last[x]};last[x]=len;}
void dfs(int x) {
for(int k=last[x],y;k;k=a[k].next)
if((y=a[k].y)^fa[x]) {
fa[y]=x;
dep[y]=dep[x]+1;
dfs(y);
sz[x]+=sz[y];
}
q.push(dep[x]-sz[x]);
sz[x]++;
}
int main() {
qr(n); qr(m);
for(int i=1,x,y;i<n;i++)
qr(x),qr(y),ins(x,y),ins(y,x);
dfs(1);
while(m--) ans+=q.top(),q.pop();
pr2(ans);
return 0;
}
有點思維難度.
有個簡單性質.
對於確定的,那麼離越遠,總代價越大.
也就是我們取中間的決策優於取兩邊的決策.(決策包容性)
所以我們可以枚舉所有兩端爲的情況,然後用二分找到中間位置即可.
int T,a[N],b[N],c[N],n,m,q;
ull ans;
void upd(ll x,ll y,ll z) {
ans=min(ans,(ull)(x-y)*(x-y)+(x-z)*(x-z)+(y-z)*(y-z));
}
int main() {
a[0]=b[0]=c[0]=-1e9;
qr(T); while(T--) {
qr(n); qr(m); qr(q);
for(int i=1;i<=n;i++) qr(a[i]);
sort(a+1,a+n+1);
for(int j=1;j<=m;j++) qr(b[j]);
sort(b+1,b+m+1);
for(int i=1;i<=q;i++) qr(c[i]);
sort(c+1,c+q+1);
a[n+1]=b[m+1]=c[q+1]=2e9;//注意邊界
ans=-1;
int x=1,y=1;
while(x<=n) {//x,y
while(y<m&&b[y]<=a[x]) y++;
for(int t=-1,*p;t<=0;t++)
upd(a[x],b[y+t],*(p=lower_bound(c+1,c+q+2,(a[x]+b[y+t])/2))),
upd(a[x],b[y+t],*(--p));
x++;
}
x=y=1;
while(x<=n) {//x,z
while(y<q&&c[y]<=a[x]) y++;
for(int t=-1,*p;t<=0;t++)
upd(a[x],c[y+t],*(p=lower_bound(b+1,b+m+2,(a[x]+c[y+t])/2))),
upd(a[x],c[y+t],*(--p));
x++;
}
x=y=1;
while(x<=m) {//y,z
while(y<q&&c[y]<=b[x]) y++;
for(int t=-1,*p;t<=0;t++)
upd(b[x],c[y+t],*(p=lower_bound(a+1,a+n+2,(b[x]+c[y+t])/2))),
upd(b[x],c[y+t],*(--p));
x++;
}
pr2(ans);
}
return 0;
}
考試的時候一眼看出要用做,可是呢…
題目要求我們用的某個前綴通過操作得到一個前綴爲的字符串.()
假設我們已經表達出了,那麼如果,就可表達出
所以很明顯這是個區間.特別地,可以匹配任意字符.因爲我們只在乎完成匹配即可.
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=3010,mod= 998244353;
void upd(int &x) {x-=mod; x+=x>>31&mod;}//x的合法範圍[0,2*mod)
int n,m,f[N][N],i,j,ans;
//f[i][j]表示t[i...j]由s[1...(j-i+1)]弄出的方案數.特別地,對於t[m]之後的字符可以匹配一切s中的字符.(我們只在乎前綴匹配)
char s[N],t[N];
int main() {
scanf("%s %s",s+1,t+1);
n=strlen(s+1);
m=strlen(t+1);
for(i=1;i<=m;i++) f[i][i]=(t[i]==s[1])*2;
for( ;i<=n;i++) f[i][i]=2;
for(i=2;i<=n;i++) {//枚舉長度
for(j=1;j+i-1<=n;j++)
upd(f[j][j+i-1]=f[j][j+i-2]*(j+i-1>m||t[j+i-1]==s[i])+f[j+1][j+i-1]*(j>m||t[j]==s[i]));
}
for(i=m;i<=n;i++) upd(ans+=f[1][i]);
printf("%d\n",ans); return 0;
}
如果次以上才判WA的話,那麼我應該可以在比賽時AC.
次操作的錯誤代碼:(想看就看吧)
int n,a[N],f[N];
ll l1,l2,n1,n2;
int main() {
qr(n); scanf("%lld %lld",&l1,&l2);
for(int i=1;i<=n;i++) {
for(int j=1;j<=2;j++) {
printf("+ %d\n",i);
fflush(stdout);
scanf("%lld %lld",&n1,&n2);
}
a[i]=sqrt(n1-l1);
l1=n1; l2=n2;
}
printf("! ");
for(int i=1;i<n;i++) printf("%d ",a[i]);
printf("%d",a[n]); fflush(stdout);
return 0;
}
我們之所以需要次操作,是因爲我們沒有利用的的條件.
觀察的變化:
如果有連續的5個數的出現次數
增加一個對應的數,則
所以如果我們已知那麼就可以用一次操作求了.
知道這個之後,我們的突破口就是就是把逼到角落().使得參數變少,解出確定的值.
只需兩次操作,即可求得的具體值.然後我們嘗試推出前面的數.
因爲這次犧牲了兩次操作,我們自然想到把剩下的操作分配給.(什麼鬼,哪自然了)
同時,假如最後取兩次的話,的值是相等的,我們是缺乏條件解出的.
所以我們考慮設計最後三次爲.
剩下的自己推一下吧~~
這題貌似:
思維難度:省選-
代碼難度:普及—
#include<cstdio>
using namespace std;
const int N=110;
int n,l1,l2,t[N],s[N],a,b,ans[N];
void q(int i,int &t,int &s) {
printf("+ %d\n",i);
fflush(stdout);
scanf("%d %d",&t,&s);
t-=l1; s-=l2;
l1+=t; l2+=s;
}
int Sqrt(int x) {
int i=1;
while(i*i<=x) i++;
return i-1;
}
int main() {
scanf("%d %d %d",&n,&l1,&l2);
for(int i=2;i<=n-2;i++) q(i,t[i],s[i]);
q(n,t[n],s[n]); q(n-1,t[n-1],s[n-1]); q(n,a,b);
ans[n]=Sqrt(a+t[n]);
ans[n-2]=b-s[n]-1;
ans[n-1]=s[n]/(ans[n-2]+1);
ans[n-3]=s[n-1]/(ans[n-2]+1)-ans[n]-2;
for(int i=n-4; i;i--)
ans[i]=(s[i+2]-ans[i+3]*ans[i+4]-(ans[i+1]+1)*ans[i+3])/(ans[i+1]+1)-1;
printf("! "); ans[1]++; for(int i=1;i<=n;i++) printf("%d ",ans[i]); return 0;
}
EA牛逼.
總結
這次比賽暴露出對貪心的生疏,和區間DP的不足,需要加強練習.