本人只做出了前四題,所以只寫前四題的題解
給出,求
和
答案對取模
這是一道送分題
這個做多了題目就是一眼的事了
它的幾何性質是一個的矩陣其所有子矩陣個數
不會推式子怎麼辦!
和博主一樣直接看吧!
第一個就不說了
第二個反正都是乘,我們直接考慮有多少個被乘了不就可以了嗎
考慮被乘的次數,在形如這樣的情況每個都有,共有個 (這樣的情況有兩個)
形如的情況對於每個都會有,共有個,所以會被乘次
/*******************************
Author:Morning_Glory
LANG:C++
Created Time:2019年09月14日 星期六 19時06分48秒
*******************************/
#include <cstdio>
#include <fstream>
#define ll long long
using namespace std;
const int maxn = 10000005;
const int mod = 998244353;
//{{{cin
struct IO{
template<typename T>
IO & operator>>(T&res){
res=0;
bool flag=false;
char ch;
while((ch=getchar())>'9'||ch<'0') flag|=ch=='-';
while(ch>='0'&&ch<='9') res=(res<<1)+(res<<3)+(ch^'0'),ch=getchar();
if (flag) res=~res+1;
return *this;
}
}cin;
//}}}
int T,n,ans1,ans2;
int s[maxn],mi[maxn];
//{{{ksm
int ksm (int a,int b)
{
int s=1;
for (;b;b>>=1,a=1ll*a*a%mod)
if (b&1) s=1ll*s*a%mod;
return s;
}
//}}}
int main()
{
s[1]=1;
for (int i=2;i<=maxn-5;++i) s[i]=1ll*s[i-1]*i%mod;
cin>>T;
while (T--){
cin>>n;
ans1=1ll*n*(n+1)/2%mod;
ans1=1ll*ans1*ans1%mod;
ans2=ksm(s[n],2*n)%mod;
printf("%d %d\n",ans1,ans2);
}
return 0;
}
魔女要測試騎士的能力,要求他維護一個長度爲的序列,每次要詢問一個區間的和。
但是魔女覺得太簡單了,騎士能輕鬆記住個數的前綴和。
於是,魔女要求他回答一個區間的和,但如果某一個數在這個區間出現了多次,這個數只能被計算一次。
這題好像是曾經的莫隊板子題,但是開大了數據範圍,於是咱的莫隊就了
換個思路
先將查詢按照從小到大排序
令表示數字上一次的出現位置
當我們找到一個數時,只要在當前位置加上,在減去即可保證不會重複計算
由於我們將查詢按照從小到大排序了
所以每個當前查詢一定經過現在這個位置
而的情況,我們已經將的答案抵消了,所以每個只會被計算一次
而現在實際上就是要求一段區間的加和,這個用樹狀數組維護就可以了
/*******************************
Author:Morning_Glory
LANG:C++
Created Time:2019年09月14日 星期六 19時18分27秒
*******************************/
#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn = 1000006;
//{{{cin
struct IO{
template<typename T>
IO & operator>>(T&res){
res=0;
bool flag=false;
char ch;
while((ch=getchar())>'9'||ch<'0') flag|=ch=='-';
while(ch>='0'&&ch<='9') res=(res<<1)+(res<<3)+(ch^'0'),ch=getchar();
if (flag) res=~res+1;
return *this;
}
}cin;
//}}}
struct Q{
int l,r,id;
}q[maxn];
int n,m;
int a[maxn],last[maxn];
ll c[maxn],ans[maxn];
bool cmp(Q a,Q b){ return a.r<b.r;}
//{{{query
ll query(int x)
{
ll res=0;
while(x>0){ res+=c[x];x-=x&-x;}
return res;
}
//}}}
//{{{insert
void insert(int x,int v)
{
while(x<=n){ c[x]+=v;x+=x&-x;}
}
//}}}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++) cin>>q[i].l>>q[i].r,q[i].id=i;
sort(q+1,q+m+1,cmp);
int t=1;
for(int i=1;i<=n;i++){
if(last[a[i]]) insert(last[a[i]],-a[i]);
insert(i,a[i]);
while(i==q[t].r) ans[q[t].id]=query(q[t].r)-query(q[t].l-1),t++;
last[a[i]]=i;
}
for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
return 0;
}
小 上山拜師學藝,經過年之長的廚藝練習,已成爲當世名廚,今天他接受邀請,在衆人面前展示自己高超的廚藝。
人們給小提供了種食物,每種食物無限量供應,每種食物都有一個美味值,記爲 。
小爲了展示他的廚藝,他需要挑選出食材,使自己可以烹飪出任意正整數美味值的菜餚,初始時菜餚的美味值爲,每次加入一種食材,他可以選擇讓菜餚的美味值上升,也可以選擇讓菜餚的美味值下降(或許最後會弄出來黑暗料理?)。
作爲當世名廚,小自然知道該怎麼挑選食材最佳。可是他並不知道有多少種最佳的挑選食材方案,於是他找到了你來幫忙。
我們使用無序數列來表示從原來的種食材中挑選出了種食材,第種食材編號爲的方案。同時你需要注意,和爲同一種方案,且當時。
最佳的挑選食材方案指,挑選出 種食材種食材,讓他們能夠組合出任意正整數美味值的菜餚。
答案對取模。
又是一個計數題
計數題有很多方法,,容斥,遞推等都可以計數
最開始我打算按照一定方式不重不漏的組合開始計算
但是想了半天除了幾個錯誤的方法仍然沒什麼思路
在想的時候發現按照一定方式不如直接算不合法的
於是考慮容斥
首先我們要知道一點
能組合出任意正整數能組合出
所以我們將目標鎖定在能否組合出
合法的方法=所有方法-不能組合出的方法
考慮哪些一定能組合出
最顯然的是這樣的是合法的
而如果是個合數,設爲的一個因子
那麼也是合法的
可以想到任意只要滿足就合法
只要這個式子有解就合法
而其有解條件是
其實換個思路也可以得到
只要是互質的就可以滿足條件,因爲它們之間一個對另一個取模的剩餘系是可以得到的
或者考慮只要是不互質的數就不可以滿足條件,因爲無論他們怎麼加減,結果都會有他們的最大公約數在裏面
於是可以知道,得要弄出這樣的序列,其滿足
求這樣的數列個數就可以考慮容斥了
的序列數總序列數的序列數
考慮枚舉它們的,令表示以作爲的序列數,那麼答案就是
而是的倍數的序列數
用表示有多少個數是的倍數
是的倍數的序列數=
就是有個數可選可不選,但必須至少選一個的方案數
這樣這道題就得到解決了
/*******************************
Author:Morning_Glory
LANG:C++
Created Time:2019年09月14日 星期六 19時33分10秒
*******************************/
#include <cstdio>
#include <fstream>
#include <algorithm>
using namespace std;
const int maxn = 3005;
const int mx = 2000;
const int mod = 998244353;
//{{{cin
struct IO{
template<typename T>
IO & operator>>(T&res){
res=0;
bool flag=false;
char ch;
while((ch=getchar())>'9'||ch<'0') flag|=ch=='-';
while(ch>='0'&&ch<='9') res=(res<<1)+(res<<3)+(ch^'0'),ch=getchar();
if (flag) res=~res+1;
return *this;
}
}cin;
//}}}
int n;
int a[maxn],num[maxn],f[maxn],s[maxn],mi[maxn];
void add (int &x,int y){ x=((x+y)%mod+mod)%mod;}
//{{{gcd
int gcd (int a,int b)
{
if (!b) return a;
return gcd(b,a%b);
}
//}}}
int main()
{
mi[0]=1;
cin>>n;
for (int i=1;i<=n;++i) cin>>a[i];
for (int i=1;i<=3000;++i) mi[i]=2ll*mi[i-1]%mod;
for (int i=mx;i>=1;--i){
for (int j=1;j<=n;++j)
if (a[j]%i==0) ++num[i];
f[i]=(mi[num[i]]+mod-1)%mod;
for (int j=2;i*j<=mx;++j) add(f[i],-f[i*j]);
}
printf("%d\n",f[1]);
return 0;
}
在粉絲羣中,除了一共有個人,編號爲到。
大家準備一起膜爆,也就是說復讀次消息,並且由於這個人在膜上是統一的,所以每個人都必須至少復讀一次。
想要禁言掉一些人,但是這裏是粉絲羣,不能隨便禁言膜的人,於是定下一個規則:
如果這個人,能夠分成兩組,使得兩個組中所有人的復讀次數的加和是相同的,那麼這個人都要被禁言。
這個人開始討論,他們不想被暴政。
那麼問題來了,有多少種復讀的分配方法,使得沒法把這個人分成滿足以上條件的兩組?
然而的粉絲太多了,您只要輸出分配方法的種數以及這些分配方法中字典序第小的分配方式的異或和即可。
注意:如果有兩個人,則復讀次數分別爲與復讀次數分別爲 算兩種不同的分配方式。
這題打表找規律也可以看出來的
首先每人都至少復讀一次,就先記每人都復讀了一次
現在還剩次復讀要分給這些人,並且要使它們無法分成兩組復讀次數加和是一樣的
先考慮極端情況
若把這次機會再每人一次
那麼最終就是每人復讀兩次
當爲奇數時,這樣是滿足條件的,而爲偶數是不滿足的
若把這次機會全部給一個人,那麼那個人就有次復讀
剩下的人加起來也不會超過他的復讀次數,所以全部給一個人也是滿足條件的
再考慮普遍的情況
若有些人沒有被分到復讀次數(即只復讀了一次)
我們把復讀次數大於的人儘量平均分成兩組,兩組復讀次數分別爲
那麼一定有個人是隻復讀了一次的
這裏可以自己手玩這樣的看一看以便理解
把這些人放到那邊去,就剛好兩組平均了
所以這些都不滿足條件
綜上
只有把次復讀全部給一個人是絕對滿足的
當爲奇數時所有人都復讀兩次也是可以的
而字典序肯定是這樣子的
共有種滿足條件,當爲奇數時還要多一種
前面一堆異或起來不是就是都是可以判的
/*******************************
Author:Morning_Glory
LANG:C++
Created Time:2019年09月14日 星期六 20時36分37秒
*******************************/
#include <cstdio>
#include <fstream>
#define ll long long
using namespace std;
//{{{cin
struct IO{
template<typename T>
IO & operator>>(T&res){
res=0;
bool flag=false;
char ch;
while((ch=getchar())>'9'||ch<'0') flag|=ch=='-';
while(ch>='0'&&ch<='9') res=(res<<1)+(res<<3)+(ch^'0'),ch=getchar();
if (flag) res=~res+1;
return *this;
}
}cin;
//}}}
ll n,k;
int main()
{
cin>>n>>k;
if (n==1){ printf("1\n2\n");return 0;}
if (n&1) printf("%lld\n%lld\n",n+1,(k==n)?2:n+1);
else printf("%lld\n%lld\n",n,(n+1)^1);
return 0;
}
如有哪裏講得不是很明白或是有錯誤,歡迎指正
如您喜歡的話不妨點個贊收藏一下吧