noip模擬32 solutions
真是無語子,又沒上100,無奈死了
雖然我每次都覺得題很難,但是還是有好多上100的
戰神都200多了,好生氣啊啊啊
從題開始變難之後,我的時間分配越來越不均勻,導致每次都沒有時間做最後一題
今天直接掛掉了30pts,因為最後一題沒有注意部分分。。
T1 smooth
這個最簡單了,我考場上一秒出80pts做法,直接一波set維護
自帶排序和去重,完全不必擔心,就是時間複雜度多了個log
80pts.set
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=1e5+5;
const ll maxn=1e18;
int b,k;
ll pt[N],tot;
ll p[25]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71};
set<ll> st;
int sum;
signed main(){
scanf("%d%d",&b,&k);
if(k==1){
printf("1");
return 0;
}
st.insert(1);
while(st.size()){
set<ll>::iterator it=st.begin();
ll tmp=*it;
sum++;//cout<<*it<<endl;
//cout<<sum<<endl;
if(sum==k){
printf("%lld",tmp);
return 0;
}
for(re i=1;i<=b;i++){
if(sum+st.size()-1>=k&&tmp*p[i]>*st.rbegin())break;
if(tmp<=maxn/p[i])
st.insert(tmp*p[i]);
}
st.erase(it);
}
}
所以考完之後,看一眼題解瞬間就明白了,直接用佇列維護,不用優先佇列,
使用15個優先佇列就夠了,
因為我們每次都取所有佇列頭的最小值,保證了每次取出來的都是最小的
那麼我們更新後面的答案的時候,只能向佇列頭最小的那個佇列的後面的佇列更新值
因為我們要去重,每一個這樣更新出來的值,
一定是由一個質數乘上一個佇列頭最小值出來的,
而這個佇列頭又是由他的前面的佇列頭的最小值更新的,
這樣每次都是小的乘大的,直接保證了不重不漏。。。
AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const ll inf=0x3f3f3f3f3f3f3f3f;
ll b,k;
ll p[25]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71};
queue<ll> q[16];
signed main(){
scanf("%lld%lld",&b,&k);
for(re i=1;i<=b;i++)q[i].push(p[i]);
ll mn,who;
if(k==1){
printf("1");
return 0;
}
for(re i=1;i<k;i++){
mn=inf,who;
for(re j=1;j<=b;j++)
if(mn>q[j].front())
mn=q[j].front(),who=j;
q[who].pop();
for(re j=who;j<=b;j++){
q[j].push(mn*p[j]);
}
}
printf("%lld",mn);
}
T2 six
這個題真的是神題,二維狀壓,真牛逼!!!
我是從這個題才第一次接觸到二維狀壓的
所以其實這個題我是在zxb的指點之下才明白的,原來這個題是這麼壓的
對於一般的狀壓來說,我們只需要壓這一位是否出現了,
但是這個題他不一樣,因為你無法區分2、3和6
當你要加入一個6的時候,你發現當前的序列裡已經有了2、3這兩個質數
如果就是2、3這兩個數,那麼6就不能放進去了,但是如果是6的話,那還可以繼續放
這是我們最難區分的點,所以我們需要把這兩種情況分開,
對於每個可以放到序列裡的數來說,最多包含6個質數,所以我們就直接標記他的每一個質數
這時候你肯定會大叫,這什麼玩意,舉個例子:
B為6,那麼2是他的第一個質因子,3是第二個
2:01=1
3:10=2
6:11=3
我們把這些數拆成這樣的狀態,所以這就是為什麼資料範圍只有6
我們再對這些拆分進行狀壓,判斷這樣的數是否存在,直接用map記憶化搜尋就完了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
#define pa pair<long long,long long>
#define mpa(x,y) make_pair(x,y)
#define fi first
#define se second
const ll mod=1e9+7;
ll n;
map<pa,ll> mp;
ll sum[1<<6],id[1<<6];
pa ys[10];
int top;
ll dfs(ll s1,ll s2){
map<pa,ll>::iterator it=mp.find(mpa(s1,s2));
if(it!=mp.end())return it->se;
mp.insert(mpa(mpa(s1,s2),1));
it=mp.find(mpa(s1,s2));
for(re i=1;i<(1<<top);i++){
int num=0;
bool flag=0;
for(re j=1;j<(1<<top);j++){
if(!(i&j))continue;
if((s1>>j-1)&1)num++;
if((s2>>j-1)&1)flag=1;
if(flag||num>=2)break;
}
if(flag||num>=2)continue;
if((s1>>i-1)&1)it->se=(it->se+sum[i]*dfs(s1^(1ll<<i-1),s2|(1ll<<i-1))%mod)%mod;
else it->se=(it->se+sum[i]*dfs(s1|(1ll<<i-1),s2)%mod)%mod;
}
return it->se;
}
signed main(){
scanf("%lld",&n);
for(ll i=2;i*i<=n;i++){
if(n%i)continue;
ys[++top].fi=i;
while(n%i==0){
ys[top].se++;
n/=i;
}
}
if(n!=1)ys[++top].fi=n,ys[top].se=1;
for(re i=1;i<=top;i++)id[1<<i-1]=i;
sum[0]=1;for(re i=1;i<(1<<top);i++)
sum[i]=sum[i^(i&(-i))]*ys[id[i&(-i)]].se%mod;
printf("%lld",dfs(0,0)-1);
}
考場上我直接去容斥了,然後發現,這個好像和順序有關,2、3、6不行,但是2、6、3可以
T3 walker
這個簡單哈哈哈,雖然我考場上寫都沒寫
但是我還沒見過這麼出題的,竟然讓我搞隨機化,讓我列舉50組資料,一定能找到答案
還統計了一下失敗的概率,這就靠人品了,rp++
就每次列舉兩組資料,直接高斯約旦求解
注意找這個角度的時候,判斷是正的還是負的,要不然WA死
AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
#define pa pair<long long,long long>
#define mpa(x,y) make_pair(x,y)
#define fi first
#define se second
const ll mod=1e9+7;
ll n;
map<pa,ll> mp;
ll sum[1<<6],id[1<<6];
pa ys[10];
int top;
ll dfs(ll s1,ll s2){
map<pa,ll>::iterator it=mp.find(mpa(s1,s2));
if(it!=mp.end())return it->se;
mp.insert(mpa(mpa(s1,s2),1));
it=mp.find(mpa(s1,s2));
for(re i=1;i<(1<<top);i++){
int num=0;
bool flag=0;
for(re j=1;j<(1<<top);j++){
if(!(i&j))continue;
if((s1>>j-1)&1)num++;
if((s2>>j-1)&1)flag=1;
if(flag||num>=2)break;
}
if(flag||num>=2)continue;
if((s1>>i-1)&1)it->se=(it->se+sum[i]*dfs(s1^(1ll<<i-1),s2|(1ll<<i-1))%mod)%mod;
else it->se=(it->se+sum[i]*dfs(s1|(1ll<<i-1),s2)%mod)%mod;
}
return it->se;
}
signed main(){
scanf("%lld",&n);
for(ll i=2;i*i<=n;i++){
if(n%i)continue;
ys[++top].fi=i;
while(n%i==0){
ys[top].se++;
n/=i;
}
}
if(n!=1)ys[++top].fi=n,ys[top].se=1;
for(re i=1;i<=top;i++)id[1<<i-1]=i;
sum[0]=1;for(re i=1;i<(1<<top);i++)
sum[i]=sum[i^(i&(-i))]*ys[id[i&(-i)]].se%mod;
printf("%lld",dfs(0,0)-1);
}