https://codeforces.com/contest/1256
題意:給你a個價值n的物品和b個價值1的物品,問是否存在取物方案使得價值為s
題解:min(s/n,a)*n+b>=s?YES:NO
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<algorithm> using namespace std; int a,b,n,s; int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d%d%d",&a,&b,&n,&s); printf(min(s/n,a)*n+b>=s?"YES\n":"NO\n"); } return 0; }
B:Minimize the Permutation【貪心】
題意:給定一個全排列,你可以選定一個位置i,交換ai和ai+1,每個i只能選一次,問最終最小的排列是什么
題解:從小到大枚舉,每次盡可能左移即可
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<algorithm> using namespace std; int T,n; int a[101],ad[101],fl[101]; int main() { scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n;i++){scanf("%d",&a[i]);ad[a[i]]=i;fl[i]=0;} int r=1; for(int i=1;i<=n;i++) { for(int j=ad[i]-1;(!fl[j]) && j>0 && a[j]>a[j+1];j--) { swap(a[j],a[j+1]); swap(ad[a[j]],ad[a[j+1]]); fl[j]=1; } } for(int i=1;i<=n;i++)printf("%d%c",a[i]," \n"[i==n]); } return 0; }
C:Platforms Jumping【貪心】
題意:給定一個長度為n的池塘,m塊木板以及他們各自的長度,每次你能從i跳到[i+1,i+d],木板之間的相對位置不能移動,求怎么放置木板能使得從0跳到n+1
題解:貪心放到最遠端,如果達到當前木板的最右起點限制,則從最右起點限制開始放
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<algorithm> #include<cstring> #include<string> #define ll long long using namespace std; int n,m,d; int l[1001],le[1011],ans[1001]; int main() { scanf("%d%d%d",&n,&m,&d); for(int i=1;i<=m;i++)scanf("%d",&l[i]); le[m+1]=n+1; for(int i=m;i>0;i--)le[i]=le[i+1]-l[i]; int now=0; for(int i=1;i<=m;i++) { if(now+d<=le[i]) { for(int j=1;j<=l[i];j++)ans[now+d+j-1]=i; now=now+d+l[i]-1; } else { for(int j=1;j<=l[i];j++)ans[le[i]+j-1]=i; now=le[i]+l[i]-1; } } if(now+d<=n)return !printf("NO\n"); printf("YES\n"); for(int i=1;i<=n;i++)printf("%d%c",ans[i]," \n"[i==n]); return 0; }
D:Binary String Minimizing【貪心】
題意:給你一個二進制串,你可以交換ai和ai+1,問交換次數≤k次的最小串
題解:每次貪心將最前面的0移到前面即可
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<algorithm> #include<cstring> #include<string> #define ll long long using namespace std; int T,n;ll k; int ad[1000011],adn; char a[1000011]; int main() { scanf("%d",&T); while(T--) { scanf("%d%I64d%s",&n,&k,a); adn=0; for(int i=0;i<n;i++) { if(a[i]=='0') { if(k>=i-adn){swap(a[i],a[adn]);k-=i-adn;adn++;} else {swap(a[i],a[i-k]);break;} } } printf("%s\n",a); } return 0; }
E:Yet Another Division Into Teams【DP】
題意:給定n個數,要求你將數分組,每組數至少有三個,每組的值為這組最大值減去最小值,求怎么分使得所有組的值加起來最小
題解:
先從小到大排序
F[i][1/2/3]表示前i個數,最后一組大小為1/2/3及以上時的最小答案,G[i][1/2/3]表示當前狀態的F從哪個前置狀態轉移過來
最終答案就是F[n][3],然后根據G倒推出分組情況即可
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<algorithm> #include<cstring> #include<string> #define ll long long using namespace std; int n; struct node { int v,bh,g; }a[200001]; bool cmp(const node &T1,const node &T2){return T1.v<T2.v;} bool cmp2(const node &T1,const node &T2){return T1.bh<T2.bh;} ll f[200001][4],g[200001][4]; int main() { scanf("%d",&n); for(int i=1;i<=n;i++){scanf("%d",&a[i].v);a[i].bh=i;} sort(a+1,a+1+n,cmp); f[3][3]=a[3].v-a[1].v; g[3][3]=2;g[2][2]=1; for(int i=4;i<=n;i++) { f[i][1]=f[i-1][3];g[i][1]=3; if(i>4)f[i][2]=f[i-1][1]+a[i].v-a[i-1].v,g[i][2]=1; if(i>5) { if(f[i-1][3]<=f[i-1][2])f[i][3]=f[i-1][3]+a[i].v-a[i-1].v,g[i][3]=3; else f[i][3]=f[i-1][2]+a[i].v-a[i-1].v,g[i][3]=2; } else { f[i][3]=f[i-1][3]+a[i].v-a[i-1].v,g[i][3]=3; } } int j=3,t=1; for(int i=n;i>0;i--) { a[i].g=t; if(j==1)t++; j=g[i][j]; } sort(a+1,a+1+n,cmp2); printf("%I64d %d\n",f[n][3],t-1); for(int i=1;i<=n;i++)printf("%d%c",a[i].g," \n"[i==n]); return 0; }
F:Equalizing Two Strings【思維】
題意:給你兩個長度相等的串,每次你可以選定一個長度k,在串1中選定起點s1,在串2中選定起點s2,同時翻轉兩個串ch1[s1,s1+k-1],ch2[s2,s2+k-1],求是否存在翻轉方案使得兩個字符串最終相等
題解:
首先當兩個字符串的字符集不相等時一定為NO
考慮翻轉長度為k的字符串,其操作相當於若干次翻轉長度為2的字符串,所以我們只考慮翻轉長度為2的字符串
根據題意,翻轉即為交換i和i+1兩個字符
考慮交換i,j兩個字符,則需要(j-i)+(j-(i+1))次操作,則一定為奇數
考慮交換i,j,k三個字符,則先交換i到正確位置,再交換j,k,相當於兩次交換兩個字符的操作,則一定為偶數
對於每一組交換組,若其大小為奇數,那么操作次數一定為偶數,存在方案交換
對於每一組交換組,若其大小為偶數,那么這樣的組存在偶數個,則存在方案交換,否則不存在方案交換
特殊的,如果字符串中出現兩個及以上相同的字母,那么一定存在方案交換,因為我只需要將兩個相同字符換到相鄰位置
然后對第二個字符串永遠操作交換兩個相同字母,那么第二個字符串永遠不會變,則此時一定存在方案交換使得字符串1變成字符串2
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<algorithm> #include<cstring> #include<string> #define ll long long using namespace std; int T,n; char ch1[200001],ch2[200001]; int cnt1[30],cnt2[30],ffl[30]; int main() { scanf("%d",&T); while(T--) { memset(cnt1,0,sizeof(cnt1)); memset(cnt2,0,sizeof(cnt2)); scanf("%d%s%s",&n,ch1,ch2); for(int i=0;i<n;i++)cnt1[ch1[i]-'a'+1]++,cnt2[ch2[i]-'a'+1]++; int fl=0; for(int i=1;i<=26;i++)if(cnt1[i]!=cnt2[i]){fl=1;break;} if(fl){printf("NO\n");continue;} for(int i=1;i<=26;i++)if(cnt1[i]>1){fl=1;break;} if(fl){printf("YES\n");continue;} int cnt=0; for(int i=0;i<n;i++)cnt2[ch2[i]-'a'+1]=i; memset(ffl,0,sizeof(ffl)); for(int i=0;i<n;i++) { if(ffl[i])continue; ffl[i]=1;int tcnt=1; for(int j=cnt2[ch1[i]-'a'+1];j!=i;j=cnt2[ch1[j]-'a'+1])tcnt++,ffl[j]=1; if(!(tcnt&1))cnt++; } printf(cnt&1?"NO\n":"YES\n"); } return 0; }